594   PHP

一,背景:

1,用 PHP 写 API 时,通过 POST 方式来进行交互 json 数据

2,常用的接收 POST 数据使用 PHP 的全局变量 $_POST

 

二,问题:

1,API 写好后,发现有人调用成功,有人失败,见鬼了
2,查看日志,发现调用失败的要不是 POST 数据为空,要不就是数据格式异常
3,一开始以为他们调用接口的代码有问题,程序员都会觉得自己代码没问题,事实证明一般都是自己问题

 

三,解释:

1,经过网上查询,发现是 PHP 接收 POST 数据的代码有问题

全局变量 $_POST 接收 POST 数据是有条件的
官网已经写得非常清楚

An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.

翻译过就是
$_POST 接收的参数条件, HTTP 请求头 Content-Type 必须是 application/x-www-form-urlencoded 或者 multipart/form-data

 

2,一般的 web 网页表单 form 提交,符合以上的请求头要求,但是这次的 API 交互数据格式是 json ,部分调用 API 的请求头设置为 Content-Type: application/json ,所以 $_POST 接收不到数据

 

3,知道原因那就好办了,在接收 POST 参数时做个兼容性处理,通过 php://input 获取请求头为 Content-Type: application/json 的参数

关于 php://input ,官网也有解释

php://input is a read-only stream that allows you to read raw data from the request body. In the case of POST requests, it is preferable to use php://input instead of $HTTP_RAW_POST_DATA as it does not depend on special php.ini directives. Moreover, for those cases where $HTTP_RAW_POST_DATA is not populated by default, it is a potentially less memory intensive alternative to activating always_populate_raw_post_data. php://input is not available with enctype="multipart/form-data".

简单翻译下,除了请求头 enctype(Content-Type) 是 multipart/form-data 之外,php://input 都能接收到请求 request body 中参数,而 POST 方式会把参数放在 request body 中,GET 方式是放在 url 的

 

 

4,接手 POST 参数的兼容性代码如下

$header_content_type=$header['Content-Type'];
$form_header_type = array('multipart/form-data','application/x-www-form-urlencoded');
if(in_array($header_content_type,$form_header_type)){
	$post_data = $_POST;
}else{
	$post_data = file_get_contents('php://input');
}




Leave a Reply

Your email address will not be published. Required fields are marked *