Postman以POST方式提交表单的方式
由于是前后端分离的项目,本地用postman测试好了之后就提交接口给前端用,却发现前端调用的时候总是400。奇怪的很,前端各种方法尝试了都不行,然后我抓包看了下,发现事情并不简单。
接口是这样的:
- https://tools.ietf.org/html/rfc2616#page-54
- https://stackoverflow.com/questions/611906/http-post-with-url-query-parameters-good-idea-or-not
- https://segmentfault.com/a/1190000018774494
- https://imququ.com/post/four-ways-to-post-data-in-http.html#toc-0
- https://tools.ietf.org/html/rfc7231#page-17
- https://stackoverflow.com/questions/14710061/is-it-valid-to-combine-a-form-post-with-a-query-string/14710450
- https://www.w3.org/2001/tag/doc/whenToUseGet.html 使用GET和POST的建议,一篇非常不错的文章
可以看到,由于此接口提交的参数有点特殊,参数中有个字段的值是JSON字符串,所以直接使用原始的JSON字符串会报错,因为像“[]”这样的字符并不能被合理的解析,接口返回了400。因此为了后端能接受这个字符串,我做了下URL Encode。即,把JSON字符串编码后再传递给后端:
这样提交就没问题了,可以成功返回success。
前端是使用form表单提交的,但是提交的时候一直提示JSON解析失败,提醒前端要对JSON字符串进行URL编码,但是前端说编码了,还是这样,看了下chrome的控制台请求参数,确实是编码了:
这就让我很纳闷了,都是一样的参数为什么不行?难道我的postman有问题?于是不信邪的我抓包看下能不能找到点什么东西,于是下了个Fidder,新版已经改版了叫Fiddler Everywhere,界面比老版更清爽一点。抓个Postman的包看下:
发现有点奇怪,一般POST提交的参数都是在最下面的,这里直接是拼在了URL后面,是GET方式的那种,但是Content-Type又没有问题,于是查了些文章,发现Postman用Form表单提交应该在Body中编辑参数,而我一直是在Param中编辑参数的,这里编辑的参数就是直接拼接在URL后面,怪不得需要URL编码,原来是我搞错方式了:
换了种方式试下,果然,不要手动编码,因为程序会自动处理编码问题,手动编码就相当于编码了两次,后端只解析一次当然无法识别了。抓个包看下请求:
参数部分是自动编码的:
代码的问题解决了,新的问题来了,为什么POST方式提交的参数接在URL后面也可以?有什么不同?
首先,根据RFC的规范,URL的格式为:
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
除此以外并没有其他特别的限制。
因此将参数直接写在URL上从语法上来说没什么问题,只是编码上需要注意点,处理一些URL的保留字符即可。那么GET和POST的使用看起来似乎区别不那么大?
这里摘取参考连接中文章的一个例子:
场景1:Dan购买了一部新的无线电话,并希望与他的同事分享有关它的信息。根据电话底部的提示“ CAT.NO.43-893”,Dan访问了电话制造商的网站。在站点的搜索框中输入编号,Dan提取相关信息。但是,由于网站设计者为此只读操作创建了POST Web表单而不是GET Web表单,因此Dan无法将查询添加为书签,也无法将查询作为URI发送给其同事(潜在客户),也无法获取任何内容。正确使用HTTP GET可以带来其他好处。网站设计者应该提供对目录信息的GET访问。
场景2:我的银行允许我通过Web查询我支票帐户的当前信息。他们提供给我的URI包括我的帐号。这是我不想出现在URI中的敏感信息,这是因为,当我点击银行网站到其广告客户的网站的链接时,我的帐号信息可能会出现在广告客户的服务器日志中。但是银行允许我建立安全的HTTPS连接,而并没有将我的帐号从URI移到POST请求体中。通过安全连接检索信息不仅让我更有信心,而且我的浏览器知道不会在安全连接后向我访问的下一个站点公开敏感信息。因此,我仍然可以在我的帐户页面上添加书签而不泄露敏感信息。
不知道这两个场景是否能让你有什么想法。
我的感受可以引用一句回答:
It depends what you need to do.