我试图压缩一堆文件并将其上传到远程服务器(也是由nodejs编写并使用multiparty进行表单处理)
但我想要实现的是没有临时文件。这意味着":以流形式创建zip存档,并通过request
模块直接上传流。"
所以我写了一些测试代码,首先是接收上传的服务器:
var multiparty = require('multiparty');
var http = require('http');
var util = require('util');
http.createServer(function(req, res) {
if (req.url === '/upload' && req.method === 'POST') {
// parse a file upload
var form = new multiparty.Form({encoding: null});
console.log("what?");
form.parse(req, function(err, fields, files) {
if (err) {
console.error(err);
}
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
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>'
);
}).listen(8080);
然后我只使用child_process执行zip
命令,但是我没有创建临时文件,而是将存档输出到stdout以创建流:
/*
upload a manually-created readable stream from string output from zip command.
*/
var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
var zipCmd = 'zip -r9 - ' + dir;
var Stream = require('stream');
var request = require('request');
var fs = require('fs');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
if (err) console.error(err);
var rs = Stream.Readable({encoding: null});
rs.push(stdout);
rs.push(null);
var req = request.post('http://127.0.0.1:8080/upload', function(err, httpResponse, body) {
if (err) console.error(err);
console.log(body);
});
var form = req.form();
form.append('image', rs);
})
但是在我运行上传脚本后,服务器返回
{ [Error: stream ended unexpectedly] status: 400, statusCode: 400 }
似乎这个可读流有问题。
以检查该流内容中是否存在任何损坏。我将脚本修改为使用临时文件。
/*
first write the stream content to a temp file, then
upload a new stream from the temp file.
*/
var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
var zipCmd = 'zip -r9 - ' + dir;
var Stream = require('stream');
var request = require('request');
var fs = require('fs');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
if (err) console.error(err);
var rs = Stream.Readable({encoding: null});
rs.push(stdout);
rs.push(null);
var ws = fs.createWriteStream('/Users/drakedan/Desktop/test.zip');
rs.pipe(ws);// create a temp file.
rs.on('end', function(){
var req = request.post('http://127.0.0.1:8080/upload', function(err, httpResponse, body) {
if (err) console.error(err);
console.log(body);
});
var form = req.form();
form.append('image', fs.createReadStream('/Users/drakedan/Desktop/test.zip')); // readstream from temp file
});
});
这次,服务器接受该文件。
received upload:
{ fields: {}, files: { image: [ [Object] ] } }
并且可以成功解压缩临时文件,这意味着不会损坏内容。
所以我的问题是:
处理这种情况的正确方法是什么?
fs.createReadStream
与我手动创建的可读流之间有什么区别。
我是否有可能在整个过程中流动?
我做错了什么?
答案 0 :(得分:0)
经过深入挖掘后,我想我找到了解决问题的方法。
基于我的假设,SDWebImage
错误主要是因为服务器端不知道流实际结束的位置。说文件的大小是未知的。我从blog获得了一些提示,它改变了stream ended unexpectedly
标题。在我这样做之后,服务器似乎接受了表单,而不是作为上传文件而是作为普通字段。
这是一个进步!然后我重温了form-data和request我终于想出了正确的方法。
有两种方法可以解决问题:
使用自定义表单选项构造formData,将stdout直接作为内容。给它一个正确的内容类型然后提交它,并完成它。
transfer-encoding:'chunked'
2.使用手动创建的可读流。虽然它似乎没必要
在这种情况下,但仍然很好知道。关键点是定义knownLength ,否则会发生var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
var zipCmd = 'zip -r9 - ' + dir;
var Stream = require('stream');
var request = require('request');
var fs = require('fs');
var FormData = require('form-data');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
if (err) console.error(err);
var form = new FormData();
form.append('image', stdout, {
filename: 'upload.zip',
contentType: 'application/zip, application/octet-stream'
});
form.submit('http://127.0.0.1:8080/upload', function(err, res) {
if (err) throw err;
console.log(res);
});
});
。
stream ended unexpectedly
通过了解发生的情况,我可以使用var exec = require('child_process').exec;
var dir = '/Users/drakedan/Documents/screenshot/1457950544039/';
var zipCmd = 'zip -r9 - ' + dir;
var Stream = require('stream');
var request = require('request');
var fs = require('fs');
var FormData = require('form-data');
exec(zipCmd, {encoding: null}, function(err, stdout, stderr) {
if (err) console.error(err);
var rs = Stream.Readable({encoding: null});
rs.push(stdout);
rs.push(null);
var form = new FormData();
form.append('image', rs, {
filename: 'upload.zip',
contentType: 'application/zip, application/octet-stream',
knownLength: 116089 // necessary if using custom steam
});
form.submit('http://127.0.0.1:8080/upload', function(err, res) {
if (err) throw err;
console.log('done');
});
});
更改代码以完成工作。使用自定义文件选项
request