Node中POST请求的正确处理方式

640?wx_fmt=png


Node的 http 模块只对HTTP报文的头部进行了解析,然后触发 request 事件。如果请求中还带有内容部分(如 POST 请求,它具有报头和内容),内容部分需要用户自行接收和解析。


通过报头的 Transfer-EncodingContent-Length 即可判断请求中是否带有内容



字段名称含义
Transfer-Encoding指定报文主体的传输编码方式
Content-Length报文主体的大小


写个方法判断是否有报文主体


 
 
const hasBody = function(req) {	
  return  'transfer-encoding'  in  req.headers  ||  'content-length' in req.headers;	
};

接收数据

报文内容部分会通过 data 事件触发,我们只需以流的方式处理即可,不要在订阅 data 事件的时候使用 += 的形式拼装数据,这样会乱码的。


 
 
function handle(req, res) {	
  if (hasBody(req)) {	
    var buffers = [];	
    req.on('data', function (chunk) {	
      buffers.push(chunk);	
    });	
    req.on('end', function () {	
      const POST = Buffer.concat(buffers).toString();	
    });	
  }	
}

1. POST发送的是表单的数据

如果在页面中使用表单提交一个post请求,我们的代码大概是这样的。


 
 
<form action="/upload" method="post">	
    <label for="username">用户名:</label>	
    <input type="text" name="username" id="username" />	
    <label for="password">密码:</label>	
    <input type="password" name="password" id="password" />	
    <input type="submit" />	
  </form>


默认的表单提交,请求头中的 Content-Type 字段值为 application/x-www-form-urlencoded


 
 
Content-Type: application/x-www-form-urlencoded


写一个判断内容类型的方法


 
 
const mime = function (req) {	
  const str = req.headers['content-type'] || '';	
  return str.split(';')[0];	
};


它的报文体内容跟查询字符串相同


 
 
username=Tom&password=123456


解析表单数据使用querystring模块中的parse方法


 
 
const querystring = require('querystring')	
function handleForm (req, res) {	
  const isFrom = mime(req) === 'application/x-www-form-urlencoded'	
  if (hasBody(req) && isFrom) {	
    var buffers = [];	
    req.on('data', function (chunk) {	
      buffers.push(chunk);	
    });	
    req.on('end', function () {	
      let requestBody = Buffer.concat(buffers).toString();	
      requestBody = querystring.parse(requestBody)	
    });	
  }	
}

2. POST发送的是JSON的数据


如果在页面中使用axios发送post请求,我们的代码大概是这样的。


 
 
axios.post('/user', {	
  username: 'Tom',	
  password: '123456'	
})


默认的JSON提交,请求头中的 Content-Type 字段值为 application/json,在 Content-Type 中可能还附带编码信息 charset=utf-8


 
 
Content-Type: application/json; charset=utf-8


它的报文体内容跟JSON格式的字符串相同


 
 
{	
  "name": "Tom",	
  "password": "123456"	
}


解析JSON数据使用 JSON.parse 方法。


 
 
function handleJson (req, res) {	
  const isJson = mime(req) === 'application/json'	
  if (hasBody(req) && isJson) {	
    var buffers = [];	
    req.on('data', function (chunk) {	
      buffers.push(chunk);	
    });	
    req.on('end', function () {	
      let requestBody = Buffer.concat(buffers).toString();	
      try {	
        requestBody = JSON.parse(requestBody)	
      } catch (error) {	
        console.log(error)	
      }	
    });	
  }	
}

3. POST发送的是文件数据


如果在页面中使用表单提交文件请求,我们的代码大概是这样的。


 
 
<form action="/upload" method="post" enctype="multipart/form-data">	
    <input type="file" name="avatar" id="avatar">	
    <input type="submit" />	
  </form>


默认的上传文件提交,请求头中的 Content-Type 字段值为multipart/form-data,在 Content-Type 中可能还附带内容分隔符 boundary=----WebKitFormBoundary4Hsing01Izo2AHqv


 
 
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary4Hsing01Izo2AHqv


先上传一个JS文件,看看报文主体里面的格式大概是这样的,包含文件信息和文件内容,有指定的分隔符包裹。


640?wx_fmt=png


上传文件的时候是要区分文本文件和二进制文件,文本文件是要使用 utf8 编码(HTML,CSS,JavaScript),二进制文件是要使用 binary 编码(图片,视频,音频)


根据内容分隔符解析上传的图片,并且写入到文件中,下面代码暂时只处理图片格式的文件。


 
 
function handleFile(req, res) {	
  const isFile = mime(req) === 'multipart/form-data'	
  if (hasBody(req) && isFile) {	
    var buffers = [];	
    req.on('data', function (chunk) {	
      buffers.push(chunk);	
    });	
    req.on('end', function () {	
      // 处理文件名	
      let requestBody = Buffer.concat(buffers).toString('binary');	
      let file = querystring.parse(requestBody, '\r\n', ': ')	
      let fileInfo = file['Content-Disposition']	
      fileInfo = Buffer.from(fileInfo, 'binary').toString()	
      let { filename } = querystring.parse(fileInfo, '; ', '=')	
      filename = filename.slice(1, -1)	
      filename = `./static/${filename}`	
      // 处理内容	
      let boundary = req.headers['content-type'].split('; ')[1].replace('boundary=', '');	
      let contentType = file['Content-Type']	
      if (!contentType.includes('image')) return	
      let upperBoundary = requestBody.indexOf(contentType) + contentType.length;	
      let shorterData = requestBody.substring(upperBoundary)	
      let binaryDataAlmost = shorterData.trim()	
      let binaryData = binaryDataAlmost.substring(0, binaryDataAlmost.indexOf(`--${boundary}--`))	
      // 写入文件	
      fs.writeFile(filename, binaryData, 'binary', (err) => {	
        if (err) {	
          console.log('上传失败')	
        } else {	
          console.log('上传成功', filename)	
        }	
      })	
    });	
  }	
}


这就是所有处理POST请求的方式,你都学会了吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值