Node.js文件上载服务器,不带第三方模块

Node.js文件上载服务器,不带第三方模块,node.js,file-upload,multipartform-data,Node.js,File Upload,Multipartform Data,我想解析上传文件并保存,但没有任何第三个模块,但仍然没有成功。 我错过了什么角色吗 或者它需要先转换为缓冲区 var http = require('http'); const fs = require ('fs'); http.createServer(function (req, res) { if (req.url == '/fileupload') { var body = ''; req.on('data', (data) => { body +

我想解析上传文件并保存,但没有任何第三个模块,但仍然没有成功。 我错过了什么角色吗

或者它需要先转换为缓冲区

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);
var http=require('http');
常数fs=要求('fs');
http.createServer(函数(req,res){
如果(req.url='/fileupload'){
变量体=“”;
请求on('数据',(数据)=>{
body+=数据;
});
请求开启('end',()=>{
body=body.replace(/-.+-/g')。replace(/WebKit.+| Contentdata.+| Content Type.+/g');
fs.writeFile('test.png',body,(err)=>{
如果(错误)抛出错误;
log('文件已保存!');
});
决议结束(正文);
})
}否则{
res.writeHead(200,{'Content-Type':'text/html'});
res.write(“”);
res.write(“
”); res.write(“”); res.write(“”); 返回res.end(); } }).听(8080);
参考:

首先,
数据
是一个
缓冲区
。不能直接使用
+
运算符。也正因为如此,您不能使用正则表达式

你可以试试这个

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.");
}
还有另外两个函数可帮助将表单数据(允许多个文件)解析为一个对象:

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;
}

上传的问题是服务器接收到的数据不是同步的,而是块。因此,如果在收到第一个数据块后保存数据,则会丢失其余数据。因此,您必须创建一个流,并在流完成后创建文件。我用原始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>`;
}
function simple\u html\u form(){
返回`
上传
`;
}
在一个文件中写入所有三个部分,并使用节点启动该文件

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>`;
}