Nodejs 使用formidable模块实现stream方式图片上传,报错
Nodejs 使用formidable模块实现stream方式图片上传,报错
我是一nodejs新手,老板要求我能用nodejs实现stream方式上传图片,google良久,发现formidable很好用,也很受人们喜爱,然后在google找到许多例子,但是总是实现不了
var form = new formidable.IncomingForm();
form.parse( request, function( error, fields, files ) {
console.log( "Completed Parsing" );
if( error ){
response.writeHead( 500, { "Content-Type" : "text/plain" } );
response.end( "CRAP! " + error + "\n" );
return;
}
}
在这里的时候 总是报错 Error: MultipartParser.end(): stream ended unexpectedly: state = START,在github上有相关问题的讨论,研究良久仍不得其解,望各位帮忙,谢谢。
Node.js 使用 Formidable 模块实现 Stream 方式图片上传时遇到错误
背景
我在尝试使用 Node.js 的 formidable
模块来处理通过 HTTP POST 请求上传的图片文件。尽管我在网上找到了一些示例代码,但在实际操作中遇到了一些问题。
错误信息
在执行过程中,我遇到了以下错误:
Error: MultipartParser.end(): stream ended unexpectedly: state = START
示例代码及问题分析
首先,我们来看一下基本的代码框架:
const http = require('http');
const formidable = require('formidable');
http.createServer((request, response) => {
if (request.url === '/upload' && request.method.toLowerCase() === 'post') {
const form = new formidable.IncomingForm();
form.parse(request, (error, fields, files) => {
if (error) {
response.writeHead(500, { "Content-Type": "text/plain" });
response.end("CRAP! " + error + "\n");
return;
}
console.log("Completed Parsing");
// 这里可以添加处理文件的逻辑
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("File uploaded successfully!");
});
return;
}
response.writeHead(200, { "Content-Type": "text/html" });
response.end(`
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image" />
<input type="submit" value="Upload Image" />
</form>
`);
}).listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});
解决方案
上述代码中,关键点在于如何正确解析请求中的文件流。错误 Error: MultipartParser.end(): stream ended unexpectedly: state = START
通常发生在解析器尚未准备好接收数据时就已经结束了。为了解决这个问题,我们可以确保在解析之前正确地处理请求的整个内容。
以下是修正后的完整代码示例:
const http = require('http');
const formidable = require('formidable');
http.createServer((request, response) => {
if (request.url === '/upload' && request.method.toLowerCase() === 'post') {
const form = new formidable.IncomingForm();
form.uploadDir = "./uploads"; // 设置文件保存目录
form.keepExtensions = true; // 保持文件扩展名
form.on('error', (err) => {
response.writeHead(500, { "Content-Type": "text/plain" });
response.end(`Error: ${err.message}\n`);
});
form.on('end', () => {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("File uploaded successfully!");
});
form.parse(request);
return;
}
response.writeHead(200, { "Content-Type": "text/html" });
response.end(`
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image" />
<input type="submit" value="Upload Image" />
</form>
`);
}).listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});
关键点解释
form.parse(request)
: 这个方法会自动处理上传的数据,并调用相应的事件处理器。form.on('error', callback)
: 处理任何可能发生的错误。form.on('end', callback)
: 当文件上传完成后触发此回调函数。
通过这种方式,我们可以更可靠地处理文件上传请求,并且避免了由于解析器状态异常而导致的错误。
没这么用过,我把我的一个老的例子贴出来,希望有点用。测了一下,还运行正常。
var http = require('http');
var util = require('util');
var formidable = require('formidable');
var TEST_TMP = '/tmp';
var TEST_PORT = 8001;
var server = http.createServer(function(req, res) {
if (req.url == ‘/’) {
res.writeHead(200, {‘content-type’: ‘text/html’});
res.end(
‘<form action="/upload" enctype=“multipart/form-data” method=“post”>’+
‘<input type=“text” name=“title”><br>’+
‘<input type=“file” name=“upload” multiple=“multiple”><br>’+
‘<input type=“submit” value=“Upload”>’+
‘</form>’
);
} else if (req.url == ‘/upload’) {
var files = [];
var fields = [];
var form = new formidable.IncomingForm();
form.uploadDir = TEST_TMP;
form.on(‘field’, function(field, value) {
console.log(‘field event:’, field, value);
fields.push([field, value]);
});
form.on(‘file’, function(field, file) {
console.log(‘file event:’, field, file);
files.push([field, file]);
});
form.on(‘end’, function() {
util.puts(’-> upload done’);
res.writeHead(200, {‘content-type’: ‘text/plain’});
res.write(‘received fields:\n\n ‘+util.inspect(fields));
res.write(’\n\n’);
res.end('received files:\n\n '+util.inspect(files));
});
form.parse(req);
} else {
res.writeHead(404, {‘content-type’: ‘text/plain’});
res.end(‘404’);
}
});
server.listen(TEST_PORT);
util.puts(‘listening on http://localhost:’ + TEST_PORT + ‘/’);
默认的formidable会将文件部分先保存到服务器的临时目录下面,然后在通过fs的方式进行后续操作。如果你只需要保存到服务端文件系统,那么可以在formidable里面指定临时路径位置就好了。但是如果你想保存到别的设备,比如其他的能够接受stream的地方(例如分布式文件系统),那么需要重载form.onPart方法,然后判断if(part.filename),表明这是一个文件,那么part参数就是stream了。
直接使用express3就行了。它包括了formidable
最新版本的 express3 已经用 https://github.com/superjoe30/node-multiparty 别误导人家了…
根据你的描述,错误信息 Error: MultipartParser.end(): stream ended unexpectedly: state = START
表明在解析 multipart/form-data 请求时,请求流意外结束。这可能是由于客户端请求没有正确地发送完整的文件数据。
以下是一个使用 formidable
模块处理 stream 方式上传图片的完整示例,并且会解释如何正确处理错误和文件存储。
示例代码
const http = require('http');
const formidable = require('formidable');
const server = http.createServer((req, res) => {
if (req.url === '/upload' && req.method.toLowerCase() === 'post') {
// 创建一个 formidable 的 IncomingForm 对象
const form = new formidable.IncomingForm();
// 设置文件上传目录
form.uploadDir = './uploads';
// 解析请求
form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(`Error: ${err}\n`);
return;
}
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('File uploaded successfully.\n');
});
// 监听文件上传事件,确保文件被正确写入
form.on('fileBegin', (name, file) => {
// 修改文件名(可选)
file.path = `${form.uploadDir}/${Date.now()}-${file.name}`;
});
// 错误处理
form.on('error', err => {
console.error('Error during file upload:', err);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(`Error: ${err}\n`);
});
return;
}
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found\n');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
解释
- 创建 HTTP 服务器:使用
http.createServer()
创建一个简单的 HTTP 服务器。 - 设置文件上传路径:通过
form.uploadDir
设置文件上传目录。 - 解析请求:使用
form.parse()
方法解析 multipart 请求,处理表单字段和上传的文件。 - 文件上传开始事件:监听
fileBegin
事件来处理文件上传开始时的逻辑,例如修改文件名或路径。 - 错误处理:监听
error
事件以捕获并处理上传过程中的任何错误。 - 启动服务器:使用
server.listen()
启动服务器,监听端口。
确保你的前端表单正确配置为 enctype="multipart/form-data"
,并且发送的数据格式正确,这样才能避免 Error: MultipartParser.end(): stream ended unexpectedly
错误。