一个content-type引发的问题

Posted 时而宁靜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个content-type引发的问题相关的知识,希望对你有一定的参考价值。

背景介绍: 问题:报警监控显示项目的活动接口异常并报错,提示json_decode解析异常,但不必现,无法立刻判断原因。 先介绍下我们的数据传递流程: 【app客户端】发送加密数据 -------->【网关】解密-透传------>【php服务器】业务逻辑
图1.app报错页面
监控时常显示项目的某个接口报错异常,报警提示如下:
图2.报警邮件

过程分析: 很明显,json_decode($_POST['result'])出错,解析的数据格式非标准encode格式 那么查看下decode的数据呗,看是什么问题
抓包app给网关的数据(正确):
answer=["answer":"https://h5.youzan.com/v2/goods/277ola8ay4b6x?reft=1512028692491&spm=f47826345&sf=wx_menu"]
php收到网关的$_POST数据(错乱),
"answer":"[\\"answer\\":\\"https:\\/\\/h5.youzan.com\\/v2\\/goods\\/277ola8ay4b6x?reft=1512028692491","spm":"f47826345","sf":"wx_menu\\"]"
显然经过网关后,【answer字段里的值结构发生了变化】,导致解析失败。 所以就是【网关】的问题呗。 结论为时过早,还真不全是他的问题
图3.原始访问数据截图
php收到的file_get_contents('php://input')数据(正常)
answer=["answer":"https://h5.youzan.com/v2/goods/277ola8ay4b6x?reft=1512028692491&spm=f47826345&sf=wx_menu"]

由图看php原始数据记录可得,网关传递时数据格式显示是正常的,格式错误是因为php底层给$_POST赋值时(PHP生命周期第二步)错误造成,也就是说,是php的问题。但底层为什么会错乱呢?

问题解决: 两种方式指定数据传输的Content-type都为: application/x-www-form-urlencoded 细心的同学应该发现一个区别,图3中用postman模拟的数据,key对的value是被转义掉的, php底层对$_POST赋值是根据&切割的,但是网关传来的数据没有转义,所以当value中有"&"值时自动分开造成错误切割。 真相大白,原因是app在传递数据时只是做了加密处理,忘记做urlencode处理,网关透传到php服务器,造成php解析错误。找到真正的原因,那问题就好解决的,
根本解决方案:app做urlecode 临时解决方案:php做正则处理,用file_get_contents('php://input')里的方案。
$raw_str =file_get_contents('php://input');
preg_match("/&answer=(.*)]&/",$raw_str,$res);
$answer = empty($res[1])? Yii::$app->getRequest()->post('answer') : $res[1].']';




知识延伸: 本次问题解决的过程中,曝露出了一个问题,对http的content-type并不是十分熟悉,借此机会延伸学习一下。
Content-Type: 作用:说明了实体主体内对象的媒体类型(MIME) 包含类型:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/json : JSON数据格式
application/x-www-form-urlencoded :form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

着重看这么几个: 1.multipart/form-data 2.application/x-www-form-urlencoded 【默认类型】 3.application/json

1.multipart/form-data 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息; 由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
2.application/x-www-form-urlencoded     浏览器用x-www-form-urlencoded的编码方式把form数据的value值urlencode,转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。 3.raw -application/json  可以上传任意格式的文本,可以上传text、json、xml、html等

总结: 1.各php对各Content-Type的应用情况
http post传输
Content-Type 打印file_get_contents('php://input') 打印$_POST
multipart/form-data 无数据
application/x-www-form-urlencoded
application/json 无数据
所以,只要特殊记一下, 当 Content-Type==json,用 file_get_contents('php://input')接收并且json_decode,$_POST是无值的Content-Type==form/data,不要用 file_get_contents('php://input')接受
2.form-data与urlencode小知识点 Content-Type:multipart/form-data body体发送有边界值 Content-Type:application/x-www-form-urlencoded 会把参数用&链接组装,并且对value做转义操作【很关键】,详细解释

3. php://input与 $HTTP_RAW_POST_DATA区别 php://input访问请求的原始数据的只读流。不依赖于特定的 php.ini 指令 $HTTP_RAW_POST_DATA 包含 POST 提交的原始数据,不建议使用,php7已经被废弃
4.php 的curl与 linux发送curl,在www_url_encode是否会转译数据 问题: 1.php底层如何对$_POST进行赋值的,注意 Content-Type:multipart/form-data下的情况 2.file_get_contents('php://input');原理,为什么在Content-Type:multipart/form-data下无法捕获到值

参考地址: content-type: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST php://input : http://php.net/manual/zh/wrappers.php.php form-data、x-www-form-urlencoded、raw、binary: http://blog.csdn.net/ye1992/article/details/49998511



数据交互截图记录:
图1.multipart/form-data

图2.application/x-www-form-urlencoded
图3.application/json




以上是关于一个content-type引发的问题的主要内容,如果未能解决你的问题,请参考以下文章

压缩 AS2 主体

Content-type解析

什么是content-type类型

如何在 Retrofit 中将 InputStream 作为请求的主体发布?

使用 AFHTTPClient 将 JSON 作为 POST 请求的主体发布

响应对象Response