Nodejs处理文件上传的问题

Nodejs处理文件上传的问题

我使用的是busboy插件来处理文件上传,大致机理如下: 插件注册了一个file事件的处理程序,file事件是当文件上传完时会触发的事件。 可是当我只发出上传请求,而文件实际是undefined的时候,就一直不会触发事件,很长时间后处理才会结束。 如果连续5次发出这样的请求,Node进程就会卡住,需要几分钟才恢复过来。 后端怎样才能在这种情况下流畅运行? 不要说别发送undefined,万一别人就是这样攻击你的服务器呢? 所以我要区别出这种情况并做相应措施。 下面贴代码 req.pipe(req.busboy); console.log(req.busboy); req.busboy.on(‘file’,cont); cont是对应处理的函数


5 回复

Node.js 处理文件上传的问题

在使用 busboy 插件处理文件上传时,遇到一些常见的问题,比如文件未定义、长时间不触发事件等。为了解决这些问题,我们需要对 busboy 的事件进行更细粒度的处理,确保在文件上传失败或文件为空时能够做出相应的响应。

示例代码

const express = require('express');
const Busboy = require('busboy');

const app = express();

app.post('/upload', (req, res) => {
    const busboy = new Busboy({ headers: req.headers });

    // 处理文件事件
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        console.log(`File [${fieldname}] filename [${filename}]`);
        
        // 检查文件是否为空
        if (!filename) {
            return res.status(400).send('No file uploaded.');
        }

        // 文件处理逻辑
        file.on('data', (data) => {
            console.log(`File data received. Size: ${data.length} bytes.`);
        });

        file.on('end', () => {
            console.log('File processing finished.');
            res.send('File uploaded successfully.');
        });
    });

    // 处理其他字段
    busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
        console.log(`Field [${fieldname}]: value: [${val}]`);
    });

    // 处理所有数据接收完毕的事件
    busboy.on('finish', () => {
        console.log('All data received and processed.');
    });

    // 管道请求到 busboy
    req.pipe(busboy);
});

app.listen(3000, () => {
    console.log('Server listening on port 3000');
});

解释

  1. 初始化 Busboy:

    • 使用 Busboy 构造函数创建一个新的实例,并传递请求头信息。
  2. 处理文件事件 (file):

    • 当文件上传开始时,file 事件被触发。
    • 检查文件名 (filename) 是否为空。如果为空,则返回错误响应(例如:400 Bad Request)。
    • 在文件数据 (data) 接收过程中,可以添加日志记录或其他处理逻辑。
    • 当文件数据接收完毕 (end 事件),发送成功响应。
  3. 处理其他字段 (field):

    • 如果请求中包含其他非文件字段,这些字段的数据可以通过 field 事件获取。
  4. 处理所有数据接收完毕 (finish):

    • 当所有数据(包括文件和其他字段)接收完毕后,触发 finish 事件。
  5. 管道请求到 Busboy:

    • 将原始请求 (req) 管道到 busboy 实例,这样可以将请求中的数据流传递给 busboy 进行解析。

通过这种方式,你可以更灵活地处理文件上传过程中的各种情况,避免因文件为空或未定义导致的长时间阻塞。


呃。。你要不要试着把 pipe 放在事件注册之后? 我想不出为什么连续发出请求会卡住,node 是不怕慢客户端攻击的

在pipe之前,你需要检查request的HEADER,

  • 看看content-type是不是multipart/form-data;
  • 有没有设置boundary
  • 有咩有content-length

基于官方的例子:

var http = require('http'),
    path = require('path'),
	fs = require('fs'),
    os = require('os');

var Busboy = require(‘busboy’);

http.createServer(function(req, res) { if (req.method === ‘POST’) { //在这里做一个头部数据检查 if(!/multipart/form-data/i.test(req.headers[‘content-type’])){ return res.end(‘wrong’); }

var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
  console.log('file')
  var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
  file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function() {
  res.writeHead(200, { 'Connection': 'close' });
  res.end("That's all folks!");
});
return req.pipe(busboy);

} res.writeHead(404); res.end(); }).listen(8000, function() { console.log(‘Listening for requests’); });

在处理文件上传时,确保能够正确地处理异常情况(如 undefined 文件)是非常重要的。以下是一个基于 busboy 的示例,展示了如何处理文件上传过程中可能出现的异常情况,并确保服务器能够稳定运行。

示例代码

const express = require('express');
const Busboy = require('busboy');

const app = express();

app.post('/upload', (req, res) => {
    const busboy = new Busboy({ headers: req.headers });

    // 监听文件上传事件
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        if (!filename) {
            return res.status(400).send('No file uploaded.');
        }
        
        console.log(`File [${fieldname}] received.`);
        const saveTo = `./uploads/${filename}`;
        file.pipe(fs.createWriteStream(saveTo));
        
        file.on('end', () => {
            console.log(`File [${filename}] Finished`);
        });
    });

    // 处理字段事件
    busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated) => {
        console.log(`Field [${fieldname}]: value: ${val}`);
    });

    // 处理结束事件
    busboy.on('finish', () => {
        res.writeHead(200, { 'Connection': 'close' });
        res.end("That's all folks!");
    });

    req.pipe(busboy);
});

app.listen(3000, () => {
    console.log('Server started on port 3000');
});

解释

  1. 创建 Busboy 实例:

    • 使用 new Busboy() 创建一个新的 Busboy 实例,并传入请求头信息。
  2. 监听文件上传事件:

    • 使用 .on('file', ...) 监听文件上传事件。
    • 在事件处理函数中检查文件名是否为空 (!filename),如果为空则返回错误响应。
    • 如果文件名不为空,则将文件流写入指定目录。
  3. 处理字段事件:

    • 使用 .on('field', ...) 监听表单字段事件,并打印字段值。
  4. 处理结束事件:

    • 使用 .on('finish', ...) 监听整个请求的结束事件,然后发送成功响应。

通过这种方式,你可以确保即使接收到无效的文件数据(例如 undefined),也能够及时处理并返回错误响应,而不是让进程卡住。这样可以保证服务器的稳定性和安全性。

回到顶部