Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

无法通过this.ctx.request.body获取完整的POST数据 #1977

Closed
fanttm opened this issue Jan 17, 2018 · 21 comments
Closed

无法通过this.ctx.request.body获取完整的POST数据 #1977

fanttm opened this issue Jan 17, 2018 · 21 comments

Comments

@fanttm
Copy link

fanttm commented Jan 17, 2018

  • Node Version: 8.9.4
  • Egg Version: ^2.0.0
  • Platform: windows 10

使用jQuery发起POST请求,发送array数据到egg服务,从浏览器控制台中查看,明明发送的array长度是100,但是在egg controller中打印出this.ctx.request.body,却只有48;我已经修改了bodyParser的配置,还是不行,难道要改成Stream读取吗?

app/controller/matches.js

'use strict';

const Controller = require('egg').Controller;

class MatchController extends Controller {
  async create() {
    const {year,month,day,matches} = this.ctx.request.body;
    console.log(year, month, day, matches.length);
    this.ctx.set("Access-Control-Allow-Origin", "*");
    this.ctx.body = 'OK';
  }
}

module.exports = MatchController;

config.default.js

'use strict';

module.exports = appInfo => {
  const config = exports = {};

  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1516152437841_185';

  // add your config here
  config.middleware = [];

  config.bodyParser = {
    formLimit: '300mb',
    jsonLimit: '300mb',
    textLimit: '300mb'
  };

  return config;
};
@atian25
Copy link
Member

atian25 commented Jan 17, 2018

看下 jquery 的代码,还有 devTool 里面的 network

@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

看过,没感觉有什么问题,如下:

Request URL:http://127.0.0.1:7001/api/matches
Request Method:POST
Status Code:200 OK
Remote Address:127.0.0.1:7001
Referrer Policy:no-referrer-when-downgrade

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9
Connection:keep-alive
Content-Length:87747
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:127.0.0.1:7001
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36

Response


Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Connection:keep-alive
content-length:11
content-type:text/plain; charset=utf-8
Date:Wed, 17 Jan 2018 03:10:47 GMT
Vary:Origin
x-content-type-options:nosniff
x-download-options:noopen
x-frame-options:SAMEORIGIN
x-readtime:32
x-xss-protection:1; mode=block

@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

jquery代码应该也没有问题,我修改了array中每个元素的大小,现在jquery侧输出的array长度是52,但是在egg侧输出的长度是26

@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

koa-bodyparser需要作为plugin来显式配置引入吗?

@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

修改配置如下后,可以完整读取POST数据

  config.bodyParser = {
    enable: true,
    formLimit: '300mb',
    jsonLimit: '300mb',
    textLimit: '300mb',
    strict: true,
    // @see https://github.com/hapijs/qs/blob/master/lib/parse.js#L8 for more options
    queryString: {
      arrayLimit: 10000,
      depth: 50,
      parameterLimit: 10000,
    }
  };

通过排除,我确认是 parameterLimit: 10000, 最终起了作用,这是什么道理?

虽然可用了,但感觉用法似乎有些怪异,万一姿势不对就怕哪天爆发了,请帮忙看看~~

@atian25
Copy link
Member

atian25 commented Jan 17, 2018

因为你是通过 x-www-form-urlencoded 的方式的,这么长的一个字符串,放到 URL 上,会有风险的,一些运营商或旧版本的浏览器会截取掉的。

改为 post formdata 或 json 的方式吧

@atian25 atian25 closed this as completed Jan 17, 2018
@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

多谢!附上最终代码

config.default.js

'use strict';

module.exports = appInfo => {
  const config = exports = {};

  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1516152437841_185';

  // add your config here
  config.middleware = [];

  config.security = {
    csrf: {
      ignoreJSON: true, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 `application/json` 的请求
    },
    // methodnoallow: {
    //   enable: false
    // }, 
    // domainWhiteList: [ '*' ],
    // csrf: {
    // 	ignore: ctx => true
    // }
  };

  config.cors = {
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
    credentials: true,
    origin: () => '*'
  };

  config.bodyParser = {
    // enable: true,
    // formLimit: '300mb',
    jsonLimit: '300mb',
    // textLimit: '300mb',
    // strict: true,
    // // @see https://github.com/hapijs/qs/blob/master/lib/parse.js#L8 for more options
    // queryString: {
    //   arrayLimit: 10000,
    //   depth: 50,
    //   parameterLimit: 100000,
    // }
  };

  return config;
};

plugin.js

'use strict';

// had enabled by egg
// exports.static = true;

exports.cors = {
  enable: true,
  package: 'egg-cors',
};

matches.js

'use strict';

const Controller = require('egg').Controller;

class MatchController extends Controller {
  async create() {
    console.log(this.ctx.request.body)
    const {year,month,day,matches} = this.ctx.request.body;
    console.log(year, month, day, matches.length);
    // this.ctx.set("Access-Control-Allow-Origin", "*");
    this.ctx.body = 'OK';
  }

  // async options() {
  //   this.ctx.set("Access-Control-Allow-Origin", "*");
  // }
}

module.exports = MatchController;

jQuery.ajax

	$.ajax({
			url: "http://127.0.0.1:7001/api/matches", 
			type: "POST",
			headers: {
				"Content-Type": "application/json; charset=utf-8"
			},
			dataType: "json",
			data: JSON.stringify({
					year: year,
					month: month,
					day: day,
					matches: matchList 
			}), 
			success: function (data, status) {
				console.log("post result: ", data, status)
			}
		})

@atian25
Copy link
Member

atian25 commented Jan 17, 2018

data 应该不需要自己 stringify 的, jq 会自己处理的

@fanttm
Copy link
Author

fanttm commented Jan 17, 2018

$.post会处理,$.ajax似乎不干活

@justinli0709
Copy link

泪奔, 像找到亲人的赶脚!

我会告诉你,我调试这个问题已经快怀疑人生了吗

明明dataType是json,但是会变成urlencoded

数组100 接收死活就变少了

好吧,终于找到问题, 还好快放弃的时候换着关键词搜了一把这里.

留贴, 纪念!

@duncup
Copy link

duncup commented Feb 28, 2018

$.post会处理,$.ajax似乎不干活

$.ajax印象里也是会处理的不过要加个类似type:json的配置。好久没用了,不大确定具体参数是不是这个。仅供参考。

@justinli0709
Copy link

多谢各位!

@lylasi
Copy link

lylasi commented May 4, 2018

解决我的问题了,多谢!

@pecliu
Copy link

pecliu commented Dec 19, 2018

因为你是通过 x-www-form-urlencoded 的方式的,这么长的一个字符串,放到 URL 上,会有风险的,一些运营商或旧版本的浏览器会截取掉的。

改为 post formdata 或 json 的方式吧

x-www-form-urlencoded并不是放到url上好不好,只是一种encode的方式,data还是在post的body里的

@Kocher-JGC
Copy link

因为你是通过 x-www-form-urlencoded 的方式的,这么长的一个字符串,放到 URL 上,会有风险的,一些运营商或旧版本的浏览器会截取掉的。
改为 post formdata 或 json 的方式吧

x-www-form-urlencoded并不是放到url上好不好,只是一种encode的方式,data还是在post的body里的

说得没错,可是问题是为什么x-www-form-urlencoded方式请求数据会被截掉。希望得到解答。

@atian25
Copy link
Member

atian25 commented Dec 19, 2018

因为安全问题,默认不会解析那么长的 URL 的,避免攻击,有需要自己配置,上面有提到了。

@Kocher-JGC
Copy link

@atian25 这个我知道,post数据在body里面和url好像没什么关系吧。

@popomore
Copy link
Member

估计 content type 是 x-www-form-urlencoded,但 data 又是 json 吧

@Kocher-JGC
Copy link

@popomore @atian25
两位大哥,小弟不才,越听越糊涂了。

1、x-www-form-urlencoded方式的请求就算是JSON。JQ内部会将其转化为key-value的形式。(key1=value1&key2=value2)
2、从RFC2616约定来讲:
Url类拿到body的数据是空,应该是不会使用该类
那么如果是Body类,url和body的数据都可以拿到。
是因为post请求的数据在url上才会被截取了,还是直接把body的数据截取了,还是所有数据一起获取然后截取了。
可是数据是在this.ctx.request.body中获取的 那应该是直接获取body的数据才对啊。那如果是获取body的和url就更加没关系。 那是为什么会被截取了呢。

想了很久想不懂。希望解答一二。(•̩̩̩̩_•̩̩̩̩)

@popomore
Copy link
Member

单独提问给出重现代码吧

@egg-bot
Copy link

egg-bot commented Dec 19, 2018

Hello @fanttm. Please provide a reproducible example following the instruction.

Issues labeled by Need Reproduce will be closed if no activities in 7 days.


@fanttm,请根据这个说明提供最小可复现代码。

如果在 7 天内没有进展会被自动关闭。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants