我想解析上传文件并在没有任何第3个模块的情况下保存但仍然没有成功。 我是否会错过任何一部分?
或者它需要先转换为缓冲区吗?
var http = require('http');
const fs = require ('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var body = '';
req.on('data', (data) => {
body += data;
});
req.on('end', () => {
body = body.replace(/-.+-/g, '').replace(/WebKit.+|Contentdata.+|Content-Type.+/g, '');
fs.writeFile('test.png', body, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
res.end(body);
})
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
答案 0 :(得分:0)
req.on('data', (data) => {
body += data;
});
首先,data
是Buffer
。您无法直接使用+
运算符。也正因为如此,你不能使用正则表达式。
你可以试试这个
req.res=res;
req.on("data", onPosting).on("end", onPosted);
其中onPosting
和onPosted
的定义如下:
function onPosting(data){
if (this.data){
this.data.fill(data, this.dataIndex);
this.dataIndex += data.length;
} else {
var contentLength = +this.headers["content-length"];
if (data.length === contentLength){
this.data = data;
} else {
this.data = Buffer.alloc(contentLength);
this.data.fill(data);
this.dataIndex = data.length;
}
}
}
function onPosted(){
var boundary = extract(this.headers["content-type"], " boundary=");
var form = parseForm(boundary, this.data);
console.log(form);
this.res.end("Data Posted.");
}
还有2个函数可以帮助解析表单数据(允许多个文件)到对象:
function extract(arr, start, end){
var useIndex = typeof start === "number",
i,
j;
if (useIndex){
i = start;
if (end){
j = arr.indexOf(end, i);
return (j === -1) ? ["", -1] : [ (i === j) ? "" : arr.slice(i, j), j + end.length];
} else return arr.slice(i);
} else {
i = arr.indexOf(start);
if (i !== -1){
i += start.length;
if (end){
j = arr.indexOf(end, i);
if (j !== -1) return arr.slice(i, j);
} else return arr.slice(i);
}
return "";
}
}
function parseForm(boundary, data){
var form = {},
delimiter = Buffer.from("\r\n--" + boundary),
body = extract(data, "--" + boundary + "\r\n"),
CR = Buffer.from("\r\n\r\n"),
i = 0,
head,
name,
filename,
value,
obj;
if (body) {
while (i !== -1){
[head, i] = extract(body, i, CR);
name = extract(head, '; name="', '"').toString();
filename = extract(head, '; filename="', '"').toString();
[value, i] = extract(body, i, delimiter);
if (name){
obj = filename ? {filename, value} : {value};
if (form.hasOwnProperty(name)){ // multiple
if (Array.isArray(form[name])){
form[name].push(obj);
} else {
form[name] = [form[name], obj];
}
} else {
form[name] = obj;
}
}
if (body[i] === 45 && body[i + 1] === 45) break; // "--"
if (body[i] === 13 && body[i + 1] === 10){
i += 2; // "\r\n"
} else {
//error
}
}
}
return form;
}
答案 1 :(得分:0)
上传的问题是服务器接收的数据不是同步的而是块。因此,如果您在收到第一个块后保存数据,则会丢失其余数据。因此,您必须创建一个流并在流完成后创建文件。我用原始 js 做了一个。
const http = require('http'),
port = process.env.PORT || 9000,
host = process.env.HOST || '127.0.0.1';
//tested on node=v10.19.0, export HOST="192.168.0.103"
http.createServer(function(req, res) {
// Check if form is submitted and save its content
if (req.method == "POST") try {
store_file(req);
// This is here incase any errors occur
} catch (error) {
res.writeHead(404, {"content-type":"text/plain; charset=utf-8"});
res.end("Server Borked");
// error is object but response.write require string/buffer
console.dir(error);
return;
}
// respond with a simple html form so they can post more data
res.writeHead(200, {"content-type":"text/html; charset=utf-8"});
res.end(simple_html_form());
}).listen(port, host, () => console.dir(`Serving at http://${host}:${port}`));
将接收到的数据块存储在 tmp 文件中并创建文件
const fs = require('fs'),
os = require('os'),
path = require('path');
function store_file(req) {
// Resolve path/to/temp/file
var temp = path.resolve(os.tmpdir(), 'temp' + Math.floor(Math.random() * 10));
// This opens up the writeable stream to temporary file
var writeStream = fs.createWriteStream(temp);
// Write data in memory instead of storage
//writeStream.cork(); // disabled for causing hang
// This pipes the POST data to the file
req.pipe(writeStream);
// After the temporary file is creates, create real file
writeStream.on('finish', () => {
reader = fs.readFileSync(temp);
filename = reader.slice(reader.indexOf("filename=\"") + "filename=\"".length, reader.indexOf("\"\r\nContent-Type"));
boundary = reader.slice(0,reader.indexOf('\r\n'));
content = reader.slice(reader.indexOf('\r\n\r\n') + '\r\n\r\n'.length, reader.lastIndexOf(Buffer.from('\r\n') + boundary));
// After real file is created, delete temporary file
fs.writeFileSync(filename.toString(), content);
fs.unlinkSync(temp);
});
}
只是一个用于视口支持的简单 html 表单
function simple_html_form() {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html" charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="fileUpload">
<input type="submit" value="Upload">
</form>
</body>
</html>`;
}
将所有三个部分写在一个文件中,并使用 node 启动该文件。