Nodejs处理文件上传的问题
Nodejs处理文件上传的问题
我使用的是busboy插件来处理文件上传,大致机理如下: 插件注册了一个file事件的处理程序,file事件是当文件上传完时会触发的事件。 可是当我只发出上传请求,而文件实际是undefined的时候,就一直不会触发事件,很长时间后处理才会结束。 如果连续5次发出这样的请求,Node进程就会卡住,需要几分钟才恢复过来。 后端怎样才能在这种情况下流畅运行? 不要说别发送undefined,万一别人就是这样攻击你的服务器呢? 所以我要区别出这种情况并做相应措施。 下面贴代码 req.pipe(req.busboy); console.log(req.busboy); req.busboy.on(‘file’,cont); cont是对应处理的函数
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');
});
解释
-
初始化 Busboy:
- 使用
Busboy
构造函数创建一个新的实例,并传递请求头信息。
- 使用
-
处理文件事件 (
file
):- 当文件上传开始时,
file
事件被触发。 - 检查文件名 (
filename
) 是否为空。如果为空,则返回错误响应(例如:400 Bad Request
)。 - 在文件数据 (
data
) 接收过程中,可以添加日志记录或其他处理逻辑。 - 当文件数据接收完毕 (
end
事件),发送成功响应。
- 当文件上传开始时,
-
处理其他字段 (
field
):- 如果请求中包含其他非文件字段,这些字段的数据可以通过
field
事件获取。
- 如果请求中包含其他非文件字段,这些字段的数据可以通过
-
处理所有数据接收完毕 (
finish
):- 当所有数据(包括文件和其他字段)接收完毕后,触发
finish
事件。
- 当所有数据(包括文件和其他字段)接收完毕后,触发
-
管道请求到 Busboy:
- 将原始请求 (
req
) 管道到busboy
实例,这样可以将请求中的数据流传递给busboy
进行解析。
- 将原始请求 (
通过这种方式,你可以更灵活地处理文件上传过程中的各种情况,避免因文件为空或未定义导致的长时间阻塞。
呃。。你要不要试着把 pipe 放在事件注册之后? 我想不出为什么连续发出请求会卡住,node 是不怕慢客户端攻击的
基于官方的例子:
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');
});
解释
-
创建 Busboy 实例:
- 使用
new Busboy()
创建一个新的 Busboy 实例,并传入请求头信息。
- 使用
-
监听文件上传事件:
- 使用
.on('file', ...)
监听文件上传事件。 - 在事件处理函数中检查文件名是否为空 (
!filename
),如果为空则返回错误响应。 - 如果文件名不为空,则将文件流写入指定目录。
- 使用
-
处理字段事件:
- 使用
.on('field', ...)
监听表单字段事件,并打印字段值。
- 使用
-
处理结束事件:
- 使用
.on('finish', ...)
监听整个请求的结束事件,然后发送成功响应。
- 使用
通过这种方式,你可以确保即使接收到无效的文件数据(例如 undefined
),也能够及时处理并返回错误响应,而不是让进程卡住。这样可以保证服务器的稳定性和安全性。