nodeJs实现文件上传

本文介绍的是通过html的form标签实现文件上传功能,是一个比较简易的文件上传实例,分享一下学习成果。

客户端部分

        要上传文件必须将表单enctype设置为multipart/form-data,这个参数表示表单将会以多部件表单的形式上传

        enctype的默认值是enctype=”application/x-www-form-urlencoded”。这个值的意思指将会对表单项的内容进行url编码,所谓url编码就将请求参数转换为二进制编码。




	
	Document


	
用户名:
密码:

服务器端部分

multipart数据:
------WebKitFormBoundaryHQletlTVegg2bril
Content-Disposition: form-data; name="user"

1213
------WebKitFormBoundaryHQletlTVegg2bril
Content-Disposition: form-data; name="pass"

1234
------WebKitFormBoundaryHQletlTVegg2bril
Content-Disposition: form-data; name="f1"; filename="1.txt"
Content-Type: text/plain

aa
bbb
ccccc
------WebKitFormBoundaryHQletlTVegg2bril--

—————————————————————————————————————————————————————————————————————————————————————————

整理为如下形式:
<分隔符>\r\n数据描述\r\n\r\n数据值\r\n
<分隔符>\r\n数据描述\r\n\r\n数据值\r\n
<分隔符>\r\n数据描述1\r\n数据描述2\r\n\r\n文件内容\r\n
<分隔符>--

—————————————————————————————————————————————————————————————————————————————————————————

解析数据步骤:
1. 用<分隔符>切开数据:
[
空,
\r\n数据描述\r\n\r\n数据值\r\n,
\r\n数据描述\r\n\r\n数据值\r\n,
\r\n数据描述1\r\n数据描述2\r\n\r\n文件内容\r\n,
--
]
2. 丢弃头尾元素
[
\r\n数据描述\r\n\r\n数据值\r\n,
\r\n数据描述\r\n\r\n数据值\r\n,
\r\n数据描述1\r\n数据描述2\r\n\r\n文件内容\r\n,
]
3. 丢弃每一项头尾\r\\n
[
数据描述\r\n\r\n数据值,
数据描述\r\n\r\n数据值,
数据描述1\r\n数据描述2\r\n\r\n文件内容,
]
4. 用第一次出现的“\r\n\r\n"切分
普通数据:[数据描述,数据值]
文件类数据:[数据描述1\r\n数据描述2,文件内容]
5. 判断描述内容里面有没有“\r\n”
有——文件数据:[数据描述1\r\n数据描述2,文件内容]
没有——普通数据:[数据描述,数据值]
6. 分析“数据描述”

 

Buffer对象的分割见 https://blog.csdn.net/Seven_miao/article/details/86090683

const http=require('http')
const fs=require('fs')
const common=require('./libs/common')
const uuid=require('uuid')
const zlib=require('zlib')

let server=http.createServer((req, res)=>{
  let arr=[];

  req.on('data',data=>{
    arr.push(data)
  })
  req.on('end',()=>{
    let data=Buffer.concat(arr);
    let post={};
    let files={}
    console.log(bound)
    // data
    // 解析二进制文件上传数据
    // 获取分隔符 
//content-type:multipart/form-data; boundary=----WebKitFormBoundaryPrAAAnu8AfAbfCwj
    if(req.headers['content-type']){
      let str=req.headers['content-type'].split('; ')[1]
      if(str){
      	//获取boundary
        let boundary='--'+str.split('=')[1]
        //1. 用分隔符切分整个数据
        let arr=data.split(boundary)
        //2. 丢弃头尾两个数据
        arr.shift()
        arr.pop()
        //3. 丢弃每个数据头尾的\r\n
        arr=arr.map(buffer=>buffer.slice(2,buffer.length-2))
	//4. 每个数据的第一个‘\r\n\r\n’处切开
        arr.forEach(buffer=>{
      	  let n=buffer.indexOf('\r\n\r\n');
      	  let disposition=buffer.slice(0,n);
      	  let content=buffer.slice(n+4)
      	  disposition=disposition.toString()
      	  if(disposition.indexOf('\r\n')==-1){
      	    // 普通数据;
      	    content=content.toString();
      	    let name=disposition.split('; ')[1].split('=')[1];
      	    name=name.slice(1,name.length-1)
      	  	
      	    post[name]=content;
      	  }else{
      	    // 文件数据
      	    let [line1,line2]=disposition.split('\r\n');
      	    //line1:Content-Disposition: form-data; name="f1"; filename="1.txt"
		//line2:Content-Type: text/plain
      	    let [,name,filename]=line1.split('; ');
      	    name=name.split('=')[1]
      	    name=name.slice(1,name.length-1);

      	    filename=filename.split('=')[1]
      	    filename=filename.slice(1,filename.length-1);
      	    let type=line2.split(': ')[1]

      	    let path=`upload/${uuid().replace(/\-/g,'')}`;
      	    let rs=fs.createReadStream(filename);
      	    let ws=fs.createWriteStream(path);
      	    let gzip=zlib.createGzip();
      	    rs.pipe(gzip).pipe(ws);

      	    rs.on('error',err=>{
      	  	res.write('写入失败');
      	  	console.log(err);
      	  	res.end();
      	    });

      	    ws.on('finish',()=>{
      	    console.log('写入成功')
      	    })
      	  }
      	})
      	console.log(post)
      }
    }
    res.end()
  })
});

server.listen(8080)

 

你可能感兴趣的:(NodeJs)