使用node.js的bodyParser中间件读取post数据解析

昨天我们使用的网关转发数据时出了点问题!

情景是这样的,另一方以Post的形式向我的node.js服务推送JSON数据。但是使用bodyParser中间件后,在req.body中拿不到任何信息。

代码如下:

    app.use(bodyParser.json());
                 app.post(‘/api/*‘,function(req,res){
                             _option.onMessage({url:req.url,query:req.query,body:req.body},function(error,data){
                             res.header(‘Access-Control-Allow-Origin‘,‘*‘);
                             res.header(‘Access-Control-Allow-Headers‘,‘X-Requested-With, Content-Type‘);
                             console.log(req.params);console.log(req.body.data);
                             res.send(data);
                       });

当时百思不得其解,后来发现推送方的Post请求中请求头的Content-Type的值为"text/xml"。当时觉得和这个值有很大的关系,经过检测果然不出所料。

自己模拟一个Post请求时将Content-type设置为"application/json"那么传过来的JSON数据就可以通过bodyParser中间件后由req.body拿到。但是另一方并没有以Content-type="application/json"的形式进行传送,我们只能从自己的node.js服务下手,坚信一定会想到办法。

在网上大概找了30多分钟的资料但是没有任何眉目!!!   无奈之下只能自己读bodyParser源码,而且我始终相信读别人的代码是最快的进步方式。

果然功夫不负有心人,在长达半个多小时与bodyParser源码的”作战中“,找到了解决问题的方法!

源代码分析如下:

bodyParser一定是对Content-Type进行了校验,那么我们就从这里入手,首先找到了bodyParser.json方法,代码如下:

function json(options) {
  options = options || {}

  var limit = typeof options.limit !== ‘number‘
    ? bytes(options.limit || ‘100kb‘)
    : options.limit
  var inflate = options.inflate !== false
  var reviver = options.reviver
  var strict = options.strict !== false
  var type = options.type || ‘json‘
  var verify = options.verify || false

  if (verify !== false && typeof verify !== ‘function‘) {
    throw new TypeError(‘option verify must be function‘)
  }

  function parse(body) {
    if (body.length === 0) {
      // special-case empty json body, as it‘s a common client-side mistake
      // TODO: maybe make this configurable or part of "strict" option
      return {}
    }

    if (strict) {
      var first = firstchar(body)

      if (first !== ‘{‘ && first !== ‘[‘) {
        throw new Error(‘invalid json‘)
      }
    }

    return JSON.parse(body, reviver)
  }

  return function jsonParser(req, res, next) {
    if (req._body) return next()
    req.body = req.body || {}

    if (!typeis(req, type)) return next()

    // RFC 7159 sec 8.1
    var charset = typer.parse(req).parameters.charset || ‘utf-8‘
    if (charset.substr(0, 4).toLowerCase() !== ‘utf-‘) {
      var err = new Error(‘unsupported charset‘)
      err.status = 415
      next(err)
      return
    }

    // read
    read(req, res, next, parse, {
      encoding: charset,
      inflate: inflate,
      limit: limit,
      verify: verify
    })
  }
}

那么上述代码的 if (!typeis(req, types_))则为关键点,如果if执行了next()那下面的语句就将无法执行,我们也就无法进行read方法中,所以这个typeis方法即为突破口。

而typeis方法的位置在type-is模块中,关键代码如下:

function typeis(value, types_) {
  var i
  var types = types_

  // remove parameters and normalize
  value = typenormalize(value)

  // no type or invalid
  if (!value) {
    return false
  }

  // support flattened arguments
  if (types && !Array.isArray(types)) {
    types = new Array(arguments.length - 1)
    for (i = 0; i < types.length; i++) {
      types[i] = arguments[i + 1]
    }
  }

  // no types, return the content type
  if (!types || !types.length) return value;

  var type
  for (i = 0; i < types.length; i++) {
    if (mimeMatch(normalize(type = types[i]), value)) {
      return type[0] === ‘+‘ || ~type.indexOf(‘*‘)
        ? value
        : type
    }
  }

  // no matches
  return false;
}
................
function typenormalize(value) {
  try {
    var type = typer.parse(value)
    delete type.parameters
    return typer.format(type)
  } catch (err) {
    return null
  }
}

上述代码的value实则为传进来的req对象,也就是请求对象。那么请求对象通过‘media-typer‘模块中的parse方法将req判断为对象类型。代码如下:

function parse(string) {
  if (!string) {
    throw new TypeError(‘argument string is required‘)
  }

  // support req/res-like objects as argument
  if (typeof string === ‘object‘) {
    string = getcontenttype(string)
  }

  if (typeof string !== ‘string‘) {
    throw new TypeError(‘argument string is required to be a string‘)
  }
.................................

function getcontenttype(obj) {
  if (typeof obj.getHeader === ‘function‘) {
    // res-like
    return obj.getHeader(‘content-type‘)
  }

  if (typeof obj.headers === ‘object‘) {
    // req-like
    return obj.headers && obj.headers[‘content-type‘]
  }
}

之后在通过getcontenttype方法取出content-type的值将其返回,最后由typeis方法中的value接收。在红色的for循环中可以看出typeis函数中的types_可以为数组类型,并且会循环与value进行匹配,如果相同则直接返回。那么返回之后就不会再去执行next(),这样我们就可以继续执行下面的代码,我们就可以利用bodyParser中间件从req.body中获取数据了至于types_数组中写几种content-type值就由你的需要决定!

解决问题代码例如:

app.use(bodyParser.json( { type: [‘text/xml‘,‘application/json‘] } ));
                 app.post(‘/api/*‘,function(req,res){
                             _option.onMessage({url:req.url,query:req.query,body:req.body},function(error,data){
                             res.header(‘Access-Control-Allow-Origin‘,‘*‘);
                             res.header(‘Access-Control-Allow-Headers‘,‘X-Requested-With, Content-Type‘);
                             console.log(req.params);console.log(req.body.data);
                             res.send(data);
                       });
时间: 2024-11-03 20:45:47

使用node.js的bodyParser中间件读取post数据解析的相关文章

【node.js】readline (逐行读取)

官网链接:http://nodejs.cn/api/readline#readline_readline require('readline') 模块提供了一个接口,用于从可读流(如 process.stdin)读取数据,每次读取一行. 它可以通过以下方式使用: const readline = require('readline'); 例子,readline 模块的基本用法: const readline = require('readline'); const rl = readline.c

node.js同步及异步读取写入删除文件1

node.js初学中,在文件中同步及异步读取文档的过程: 1.同步读取: var fs=require("fs") //直接读取文档,并将同步返回值,赋值给变量 var data=fs.readFileSync("input.txt"); console.log(data.toString()); 2.异步读取: var fs=require("fs"); //通过回调函数返回获得的data值: fs.readFile("input.t

electron node.js 实现文件拖动读取文件

css/styles.css 1 .for_file_drop { 2 width: 100%; 3 height: 100px; 4 background-color: blueviolet; 5 } index.html 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 6 <title>Hello World!</title> 7 &

node.js http.get 和http.post 数据

http.get('http://codestudy.sinaapp.com', function (response) {}); node.js http post 样例: var reqData={ id:'111' }; var post_options = { host: '127.0.0.1' port: '8888', path: '/api/list', method: 'POST', headers: { 'Content-Type': 'application/x-www-fo

node.js爬虫杭州房产销售及数据可视化

现在年轻人到25岁+,总的要考虑买房结婚的问题,2016年的一波房价大涨,小伙伴们纷纷表示再也买不起上海的房产了,博主也得考虑考虑未来的发展了,思考了很久,决定去杭州工作.买房.定居.生活,之前去过很多次杭州,很喜欢这个城市,于是例行每天晚上都要花一点时间关注杭州的房产销售情况,以及价格,起初我每天都在杭州的本地论坛,透明售房网上查看,每一天的房产销售数据,但是无奈博主不是杭州本地人,看了网页上展示的很多楼盘,但是我不知道都在什么地方啊,于是乎,看到价格合适的,总是到高德地图去搜索地理位置,每次

node.js ejs模板引擎将后端数据赋值给前端js

使用node.js的Express脚手架生成项目默认是jade模板引擎,jade引擎实在是太难用了,这么难用还敢设为默认的模板引擎,过分了啊!用handlebars模板引擎写还说的过去,但笔者更愿意使用ejs,选它是因为跟Asp.Net的模板引擎有点相似吧. 先来看一下这几个模板引擎: jade模板 html head title #{title} meta(charset="UTF-8") body div.description #{description} ul - each d

【Node.js】 bodyparser实现原理解析

为什么我们需要body-parser 也许你第一次和bodyparser相遇是在使用Koa框架的时候.当我们尝试从一个浏览器发来的POST请求中取得请求报文实体的时候,这个时候,我们想,这个从Koa自带的ctx.body里面取出来就可以了嘛! 唉!等等,但根据Koa文档,ctx.body等同于ctx.res.body,所以从ctx.body取出来的是空的响应报文,而不是请求报文的实体哦 于是这时候又打算从Node文档里找找request对象有没有可以提供查询请求报文的属性,结果自然是Node文档

node.js创建简单服务测试请求数据

工具:安装node: 1,创建文件夹 server, 2 ,在server文件夹下分别创建server.js 和 package.json 文件 3,server.js 代码: 1 var express = require('express'); 2 var app=express(); 3 4 app.all('*', function(req, res, next) { 5 res.header("Access-Control-Allow-Origin", "*&quo

JAva使用DOM读取XML数据(解析)

原来一切都是有套路的 使用DOM解析XML文档步骤 1.创建解析器工厂对象 DocumentBuildFactory对象 2.由解析器工厂对象创建解析器对象,即DocumentBuilder对象 3.由解析器对象对指定XML文件进行解析,构建相应的DOM树,创建Document对象,生成一个Document对象 4.以Document对象为起点对DOM树的节点进行查询 5.使用Document的getElementsByTagName方法获取元素名称,生成一个NodeList集合, 6.遍历集合