PHP属于一门高级语言,感觉就是那种语言里面偏向于应用层的语言,再加上lnmp架构还有框架的存在,对于http请求过程中的细节封装了太多层,导致我们实际在使用过程中得到的参数已经是面目全非的样子,记录下对其探索的历程
问题出现在很久之前,有一次我用json数据去请求我们itbasic的接口,可惜没法解析,我原本以为是框架的原因,于是我开始打印$_POST中数据(post 方式提交),可是其中也是毫无结果,算了,不处理了,搞不定,反正用不到~昨天,前端小朋友再次发现这个问题,感觉很简单,为了维护自己的高大形象,就处理下吧。
首先是关于content-type 的理解:
一般是指网页中存在的Content-Type,Content-Type属性指定请求和响应的HTTP内容类型。如果未指定 ContentType,默认为text/html。
上述问题中为什么会出现指定请求和响应的HTTP内容类型,因为content-type 在request中可以设置,在response中也可以设置,在request 中设置代表我发送的请求,在response中的设置代表从服务器返回的内容。
常见的:
1 | 1.text/html |
我们在接口调用的时候常用的是后面4个
x-www-form-urlencoded
会将表单内的数据转换拼接成 key-value 对(非 ASCII 码进行编码)
编码方式应该是urlencode
还记得自己刚写php代码时候吗,那时候最基础的功能是实现一个表单提交
1 | <form enctype="application/x-www-form-urlencoded" action="http://homeway.me/post.php" method="POST"> |
然后服务器端就可以用
1 | <?php |
实际接收到的内容(通过swoole rowContent 打印出来,获取原始的POST
包体,用于非application/x-www-form-urlencoded
格式的Http POST
请求,返回原始POST
数据,此函数等同于PHP的fopen('php://input')
)
所以其实$_POST 就是对上述dept_name 进行 & explode, 然后urldecode 一下
multipart/form-data
最先接触这个东西的时候是文件上传的时候
postman 中发送请求
平时我测试接口的时候经常用的是form-data, 服务端实际接受到的数据如下(swoole)
1 | multipart/form-data,将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件 |
既可以上传文件等二进制数据,也可以上传表单键值对,
所以本该用来进行上传文件的请求方式,我平时用它来进行普通接口的测试,通过这种方式提交数据也可以通过PHP 的 $_POST 来获取到 ,上述中的boundary用来分割数据
看到了postman 上面的raw吗
raw 原始类型,可以上传任意格式的文本,比如 text、json、xml、html(中文不进行编码)
其中 json,text,html 都是通过这种方式,然后添加content-type
text/xml
微信中经常用这种方式,之前在开发企业号的时候经常遇到
1 | POST http://www.homeway.me HTTP/1.1 |
php中
$_POST
只能读取application/x-www-form-urlencoded
数据,$_FILES
只能读取multipart/form-data
类型数据,(感觉$_POST 也能读取multipart/form-data 中的数据)
要读取那里面的数据只能用最原始的方法(同理json)
1 | $data = file_get_contents(‘php://input’); |
notice:
一般服务端语言如 php、python 等,以及它们的 framework,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。(我根据这个新增框架中json 数据的解析)
1 | <?php |
notice:
千万要注意:不能上来没有判断是json 就对rawContent 取到的内容进行切割,因为只有json 的时候切割才会符合我们预期,别的时候不会
上面就是post方式提交数据的几种情况,接下来我们说get方式(现在的restful api 还有delete put 等方式,我在各个文章上都没找到关于上面内容的解释,猜测一下,是不是delete put 本质上还是属于put 方式)
起因:之所以注意到get请求的这种方式,是因为再一次偶然的过程中发现get 请求的content-type 不存在,想了下确实合乎道理,get的参数都是拼接在url 上面 (file_get_contents(‘php://input’) 只能获取post请求中的输入)
注意就算是urlencode 加密,他们都是有字符编码的限制的,如果字符编码不一致,那么加密出来的结果将会不一样
同理可以联想之前做的aes-128-ecb 加密,为什么有那么多可选项,也是这个原因
这篇文章和上面那篇文章都有简单描述urlencode是怎么实现的
(这篇文章中的很多坑我们写的时候没有碰到是因为很多默认配置的原因,比如php 字符集默认配置utf8,页面配置字符集 utf-8)
所以呢在通过get 方式传递参数的时候,我们一定要注意那些中文字符 urlencode 的时候(或者别的编码方式的时候设置的字符集是什么,是gbk 还是utf8,我们忽略这个问题是因为我们经常就默认都设置成utf8 导致很多时候这些细节会被忽略)
同理联想php中也有urlencode 函数,他的字符集是怎么设置的
所以呢,当我们出现乱码的时候我们还可以这样考虑下:
- 客户端传递过来的数据进行了怎么样的加密(字符集),get方式,post方式中的www-formedate-urlencode
- 服务端传递过来的数据进行了怎么样的解密(字符集)
在post方法里所要传送的数据也要URL encode,那么他是用什么编码方式的呢?
在form所在的html文件里如果有段,那么post就会用此处指定的编码方式编码。一般大家都认为这段代码是为了让浏览器知道用什么字符集来对网页解释,所以网站都会把它放在html代码的最前端,尽量不出现乱码,其实它还有个作用就是指定form表单的post方法提交数据的 URL encode编码方式。从这里可以看出对于get方法来说,浏览器对数据的URL encode的编码方式是有浏览器设置来决定(或者在请求之前,我们提前对非asii码进行编码设置,这样决定权就从浏览器变成我们开发者),(可以用js做统一指定),而post方法,开发人员可以指定。