mscdex / busboy

A streaming parser for HTML form data for node.js
MIT License
2.84k stars 213 forks source link

Unexpected end of form #353

Closed caiodigioia closed 6 months ago

caiodigioia commented 6 months ago

Hey guys! Why am I getting this error? I found this code in a YouTube tutorial (https://www.youtube.com/watch?v=04QoJx7r_XQ&lc=UgzNYMVDuSx_ip2J56l4AaABAg), published 2 years ago. I think something may have changed. Can someone help me please? Error: Unexpected end of form at Multipart._final (/Users/caiodigioia/curso-react-native/Salao/node_modules/busboy/lib/types/multipart.js:588:17) at callFinal (node:internal/streams/writable:698:12) at prefinish (node:internal/streams/writable:710:7) at finishMaybe (node:internal/streams/writable:720:5) at Writable.end (node:internal/streams/writable:634:5) at IncomingMessage.onend (node:internal/streams/readable:705:10) at Object.onceWrapper (node:events:628:28) at IncomingMessage.emit (node:events:514:28) at endReadableNT (node:internal/streams/readable:1359:12) at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Here is my code:

Servico.routes.js: (I've noticed that the console.log('Try') does not appear in the console, so I guess there is a problem to make the try, but I don't know what is the problem)

const express = require('express');
const router = express.Router();
const Busboy = require('busboy')
const aws = require("../services/aws")
const Salao = require('../models/salao');
const Arquivo = require('../models/arquivo');
const Servico = require('../models/servico');

router.post('/', async (req, res) => {

        let busboy = Busboy({ headers: req.headers})
        console.log('Cheguei aqui')

        busboy.on('finish', async () => {

            try {
                console.log('Try')
                const { salaoId, servico } = req.body;
                let errors = [];
                let arquivos = [];

                if (req.files && Object.keys(req.files).length > 0) {

                    for (let key of Object.keys(req.files)) {
                        const file = req.files[key];

                        // blablabla.jpg
                        const nameParts = file.name.split('.'); // [blablabla, jpg] 
                        const fileName = `${new Date().getTime()}.${nameParts[nameParts.length - 1]}`
                        const path = `servicos/${salaoId}/${fileName}`

                        const response = await aws.uploadToS3(file, path)

                        if (response.error) {
                            errors.push({ error: true, message: response.message})
                        } else {
                            arquivos.push(path)
                        }
                    }
                }

                if (errors.length > 0) {
                    res.json(errors[0]);
                    return false
                }

                // Criar serviço
                let jsonServico = JSON.parse(servico);
                const servicoCadastrado = await Servico(jsonServico).save();

                // Criar arquivo
                arquivos = arquivos.map(arquivo => ({
                    referenciaId: servicoCadastrado._id,
                    model: 'Servico',
                    caminho: arquivo,
                }));

                await Arquivo.insertMany(arquivo)

                res.json({ servico: servicoCadastrado, arquivos })

            } catch (err) {
                res.json({ error: true, message: err.message })
            }
        })
        req.pipe(busboy);
});

module.exports = router;

index.js:

const express = require('express');
const app = express();
const morgan = require('morgan');
const cors = require('cors');
const busboy = require('connect-busboy')
const busboyBodyParser = require('busboy-body-parser')
require('./database');

// Middlewares
app.use(morgan('dev'));
app.use(express.json());
app.use(busboy())
app.use(busboyBodyParser())
app.use(cors())

// Variáveis
app.set('port', 8000)

// Rotas
app.use('/salao', require('./src/routes/salao.routes'))
app.use('/servico', require('./src/routes/servico.routes'))

app.listen(app.get('port'), () => {
    console.log(`WS escutando na porta ${app.get('port')}`)
})

Node Version: v18.17.0 To post to API, I'm using Insomnia, with Multpart option "dependencies": { "@aws-sdk/client-s3": "^3.521.0", "aws-sdk": "^2.1566.0", "busboy": "^1.6.0", "busboy-body-parser": "^0.3.2", "connect-busboy": "^1.0.0", "cors": "^2.8.5", "express-busboy": "^10.1.0", "formidable": "^3.5.1", "mongoose": "^8.2.0", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1" }

mscdex commented 6 months ago

The problem is apparently you're trying to use busboy three different times (via connect-busboy, busboy-body-parser, and then explicitly in your route handler). Once anything (busboy or otherwise) has consumed the entire request body, nothing else can consume it because there is no more data. That is why you're seeing the error.

caiodigioia commented 6 months ago

Thanks so much, @mscdex ! I solved the error.