Jay*_*esh 18 file-upload node.js
我在查询此问题时发现了很多帖子,但它们都是指如何将文件从浏览器上传到node.js服务器.我想将node.js代码中的文件上传到另一台服务器.我试图根据我对node.js的有限知识来编写它,但它不起作用.
function (data) {
var reqdata = 'file='+data;
var request = http.request({
host : HOST_NAME,
port : HOST_PORT,
path : PATH,
method : 'POST',
headers : {
'Content-Type' : 'multipart/form-data',
'Content-Length' : reqdata.length
}
}, function (response) {
var data = '';
response.on('data', function(chunk) {
data += chunk.toString();
});
response.on('end', function() {
console.log(data);
});
});
request.write(reqdata+'\r\n\r\n');
request.end();
})
Run Code Online (Sandbox Code Playgroud)
上述函数由生成数据的其他代码调用.
我尝试使用curl -F"file = @ <filepath>"上传相同的数据文件,上传成功.但我的代码失败了.服务器返回特定于应用程序的错误,该错误暗示上载的文件无效/损坏.
我收集了tcpdump数据并在wireshark中对其进行了分析.从我的node.js代码发送的数据包缺少多部分数据所需的边界.我在wireshark包中看到了这条消息
The multipart dissector could not find the required boundary parameter.
Run Code Online (Sandbox Code Playgroud)
知道如何在node.js代码中完成此任务吗?
mtk*_*one 13
jhcc的答案几乎就在那里.
在我们的测试中不得不为此提供支持,我稍微调整了一下.
这是适用于我们的修改版本:
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: application/octet-stream\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="my_file"; filename="my_file.bin"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
fs.createReadStream('./my_file.bin', { bufferSize: 4 * 1024 })
.on('end', function() {
// mark the end of the one and only part
request.end('\r\n--' + boundaryKey + '--');
})
// set "end" to false in the options so .end() isn't called on the request
.pipe(request, { end: false }) // maybe write directly to the socket here?
Run Code Online (Sandbox Code Playgroud)
变化是:
ReadableStream.pipe 返回管道到流,所以end永远不会被调用.相反,等待end文件读取流.request.end 将边界放在新线上.Multipart非常复杂,如果你想让它看起来像客户端通常处理"multipart/form-data",你必须做一些事情.首先必须选择一个边界键,这通常是一个随机字符串来标记部件的开头和结尾(在这种情况下,它只是一部分,因为你想发送一个文件).每个部分(或一个部分)将需要一个标题(由边界键初始化),设置内容类型,表单字段的名称和传输编码.零件完成后,您需要使用边界键标记每个零件的末尾.
我从未使用过multipart,但我认为这是可以做到的.如果我错了,请有人纠正我:
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: application/octet-stream\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="my_file"; filename="my_file.bin"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
fs.createReadStream('./my_file.bin', { bufferSize: 4 * 1024 })
// set "end" to false in the options so .end() isnt called on the request
.pipe(request, { end: false }) // maybe write directly to the socket here?
.on('end', function() {
// mark the end of the one and only part
request.end('--' + boundaryKey + '--');
});
Run Code Online (Sandbox Code Playgroud)
再说一遍,我以前从未这样做过,但我认为这是如何实现的.也许更有知识的人可以提供更多的见解.
如果你想把它作为base64或者原始二进制以外的编码发送,你必须自己做所有的管道.它最终会变得更复杂,因为你将不得不暂停读取流并等待请求上的排水事件,以确保你不会耗尽你所有的内存(如果它通常不是一个大文件)不必担心这个).编辑:实际上,没关系,你可以在读取流选项中设置编码.
如果没有Node模块已经执行此操作,我会感到惊讶.也许有人对这个问题有了更多的了解可以帮助解决这个问题,但我认为应该有一个模块可以解决这个问题.