基础 - 请求的ContentType ¶
作者:KK
发表日期:2017.11.29
默认的ContentType ¶
请求报文里的Content-Type
字段就是描述了请求报文的内容是怎样一种格式类型,比如下面一个登录POST请求报文,Content-Type 描述了报文体是 UrlEncode格式
POST http://localhost/login HTTP/1.1
Host: localhost
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4033.400
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
If-None-Match: W/"3c-YDb/aDwHTHsnfnQxdPkCcz1vPbU"
email=xxx@yyy.com&password=123456
浏览器的表单同步提交默认就是以这种 Content-Type 来组织报文体的了(包括jQuery的ajax也是),但实际上我们可以自己另外报文的形态。
自定义ContentType ¶
这个报头可能会影响服务端对请求报文的解析,比如换成application/json
,执行以下JS代码可以构造以下 Content-Type 的请求报文:
$.ajax({
url : 'http://localhost/login',
type : 'post',
dataType : 'application/json',
data : JSON.stringify({
email : 'xxx@yyy.com',
password : '123456',
})
});
请求发出后我抓到的报文是如下,注意 Content-Type 报头和报文体:
POST http://localhost/login HTTP/1.1
Host: localhost
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4033.400
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Content-Type: application/json
Content-Length: 43
If-None-Match: W/"3c-YDb/aDwHTHsnfnQxdPkCcz1vPbU"
{"email":"xxx@yyy.com","password":"123456"}
自定义的通常要自己解析 ¶
比如在PHP脚本里,如果请求报文采用了json作为报文体的格式,那么默认情况下$_POST
数组是空的,以前有内容是因为底层将 UrlEncode格式 的报文预先解析成了数组并存到$_POST
变量中,一旦报文不是这个格式,那解析器就无法解析了,此时就要靠我们自己用代码解析:
if($_SERVER['CONTENT_TYPE'] !== 'application/json'){
return;
}
$postString = file_get_contents('php://input'); //读取请求报文数据
$_POST = json_decode($postString, 1);
if(!$errorCode = json_last_error()){
print_r($_POST);
}else{
$error = '';
if($errorCode == JSON_ERROR_NONE){
$error = '没有错误发生';
}elseif($errorCode == JSON_ERROR_DEPTH){
$error = '到达了最大堆栈深度';
}elseif($errorCode == JSON_ERROR_STATE_MISMATCH){
$error = '无效或异常的 JSON';
}elseif($errorCode == JSON_ERROR_CTRL_CHAR){
$error = '控制字符错误,可能是编码不对';
}elseif($errorCode == JSON_ERROR_SYNTAX){
$error = '语法错误';
}elseif($errorCode == JSON_ERROR_UTF8){
$error = '异常的 UTF-8 字符,也许是因为不正确的编码。'; //最经常是遇到这个错误
}elseif($errorCode == JSON_ERROR_RECURSION){
$error = '被encode的数组存在互相引用的值';
}elseif($errorCode == JSON_ERROR_INF_OR_NAN){
$error = '被encode的数组存在NAN或INF的值';
}elseif($errorCode == JSON_ERROR_UNSUPPORTED_TYPE){
$error = '所传参数变量类型无法进行encode';
}
echo $error;
}
因此当收不到请求参数的时候,可以抓包看看Content-Type
是什么,而服务端是否又部署了对应的解析代码
越来越多的新平台API都使用json报文类型 ¶
因为 UrlEncode 有如下缺点:
全部值都是字符串,服务端校验转换比较麻烦
表达深层次结构关系时,路径描述符占用了太多字节导致报文体偏大,浪费不必要的带宽
写文档的时候我们虽然用结构化嵌套式的结构描述了多层参数,但是有许多程序员不擅于将这些描述转换成 UrlEncode 的编码实现
而 json 可以表达 数字、字符串、boolean、null、数组、字典,对于API设计提供了足够丰富的支持,谷歌的前端框架 Angular 也是默认发送 json 格式的报文
甚至有用xml的 ¶
比如 SOAP协议 通讯时就是使用application/xml
作为报文格式,微信公众号的接口也是这样,用 XML 会有更多考量,有更强大的支持(银行业、海运、航空等重要领域通讯都会采用 XML),但我们平时接触的项目其实一般 json 就足够了,选择自己合适的就好,最好将报文构造器和解析器封装好,并提供切换支持,要换啥就啥。