API端点接收POST数据:$_POST与file_get_contents('php://input')的差异及Khipu网关适配问询
关于Khipu支付通知POST请求的特殊处理解析
我来帮你拆解Khipu这个特殊的POST处理逻辑——作为对接过不少支付网关的开发者,我太懂这种“非常规”操作的头疼了😅
1. Khipu与其他服务的核心区别
大多数现代支付网关(比如Stripe、PayPal的Webhook)会采用application/json格式发送通知数据:请求体是JSON字符串,请求头的Content-Type设为application/json。这种情况下PHP不会自动解析请求体到$_POST,必须手动读取php://input再用json_decode解析。
而Khipu遵循的是传统Web表单的提交标准:它发送的POST请求采用application/x-www-form-urlencoded格式(就是HTML表单用method="post"提交的格式,数据是key1=value1&key2=value2这样的键值对),这也是早期Web服务最常用的POST数据格式。
2. Khipu发送POST变量的具体方式
当Khipu触发支付完成通知时,它会向你的API端点发送一个POST请求:
- 请求头的
Content-Type会被设为application/x-www-form-urlencoded - 请求体是经过URL编码的键值对字符串,比如
notification_token=abc123&transaction_id=456 - PHP会自动识别这种格式,将请求体的键值对解析到
$_POST超全局变量中,你直接通过$_POST['notification_token']就能获取对应值。
3. 为何必须通过$_POST接收?
这是由Khipu的数据发送格式直接决定的:
- 因为它用的是
application/x-www-form-urlencoded格式,PHP默认配置会自动处理这种请求,把数据填充到$_POST里,不需要你手动解析原始请求体,这是最简便且符合官方规范的方式。 - 如果强行用
json_decode(file_get_contents('php://input')),得到的会是null或者错误结果,因为原始请求体不是JSON格式,而是URL编码的字符串。
4. 你的兼容代码的合理性
你写的这段代码非常实用,能覆盖Khipu可能出现的边缘场景:
if (empty($_POST)) { //For strange posts used by Khipu $postVars = json_decode(file_get_contents('php://input')); } else { $postVars = $_POST; }
虽然Khipu标准情况下会发送application/x-www-form-urlencoded格式,但偶尔可能因为网关重试、代理服务器修改请求头、或者PHP配置(比如enable_post_data_reading被禁用、post_max_size超限)导致$_POST无法被自动填充。这时候读取原始请求体并尝试JSON解析,能兜底处理这些异常情况,确保你不会漏掉通知。
内容的提问来源于stack exchange,提问作者Marcus Edensky




