
当使用 curl 向 php 后端发送较大 json 字符串时,若直接以字符串形式传入 `curlopt_postfields`,apache 可能因请求体解析异常(如误判为非标准 post)而返回 404;正确做法是将 json 封装为关联数组键值对,并确保 content-type 与服务端接收逻辑一致。
在 Zend Server 2019.7(PHP 7.3 + Apache 2.4)环境中,你遇到的「小数据正常、大数据返回 404」现象,并非由 post_max_size 或 max_input_vars 等常见配置限制导致,而根本原因是 cURL 的 CURLOPT_POSTFIELDS 行为机制被 Apache/Zend Server 误解为“非标准表单提交”,从而触发路由或模块层面的 404 响应。
? 问题根源解析
当你写:
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); // $json_data 是纯 JSON 字符串
cURL 会以 Content-Type: application/x-www-form-urlencoded(默认)发送请求 —— 即使你手动设置了 'Content-Type: application/json' 头,PHP 的 $_POST 超全局变量仍无法自动解析该 JSON 字符串,且某些服务器环境(尤其是 Zend Server 的请求过滤模块)会对无 name=value 结构的原始 POST body 做异常处理,甚至直接拒绝路由到目标脚本(如 recon.php),最终返回 404。
✅ 注意:404 并非来自 PHP 应用层(如文件不存在),而是 Apache/Zend Server 在请求预处理阶段因无法识别有效 POST 格式而中断了请求分发。
✅ 正确解决方案:封装为表单键值对 + 显式声明 Content-Type
将 JSON 字符串作为某个字段的值,通过数组方式提交,强制 cURL 使用 multipart/form-data 或保持 x-www-form-urlencoded 但结构合规:
$json_data = '{ "Recon": [ /* ... large JSON array ... */ ] }';
$url = 'http://192.168.1.100/projectname/recon.php';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
// ✅ 关键修复:将 JSON 作为数组字段值(而非裸字符串)
curl_setopt($ch, CURLOPT_POSTFIELDS, ['json_payload' => $json_data]);
// ✅ 必须显式声明 Content-Type(否则 Apache 可能忽略)
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$result = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP Code: $http_code\n";
echo $result;? 服务端 recon.php 需同步适配
由于你已改用表单字段提交(json_payload),服务端不能再依赖 file_get_contents('php://input')(此时为空),而应从 $_POST 中读取并解码:
// recon.php
if (isset($_POST['json_payload'])) {
$raw_json = $_POST['json_payload'];
$data = json_decode($raw_json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode(['error' => 'Invalid JSON']);
exit;
}
// ✅ 正常处理 $data['Recon']...
echo json_encode(['status' => 'success', 'count' => count($data['Recon'])]);
} else {
http_response_code(400);
echo json_encode(['error' => 'Missing json_payload']);
}⚠️ 补充注意事项
不要混淆 application/json 与表单提交:若坚持用 php://input 接收原始 JSON,则必须确保 CURLOPT_POSTFIELDS 传字符串 + Content-Type: application/json,且 Apache 的 mod_security、mod_proxy 或 Zend Server 的 Web Application Firewall(WAF)未拦截非常规 Content-Type 请求 —— 这在 Zend Server 中尤为常见。
验证实际请求头:用 curl -v 或 Wireshark 抓包确认真实发出的 Content-Type 和 body 结构。
检查 Zend Server 特定限制:进入 Zend Server Admin UI → Server Config → PHP Settings,确认 suhosin.post.max_name_length、suhosin.request.max_value_length(如有启用 Suhosin)未截断长字段名或值。
-
替代方案(推荐用于纯 API 场景):如需真正 RESTful 设计,建议统一使用 file_get_contents('php://input') + 原始 JSON 提交,并在 Apache 配置中显式允许:
# 在虚拟主机或 .htaccess 中
RewriteEngine On # 确保 JSON 请求不被重写规则误判 RewriteCond %{CONTENT_TYPE} application/json RewriteRule .* - [E=HTTP_CONTENT_TYPE:application/json]
通过将 JSON 封装为 CURLOPT_POSTFIELDS 数组字段,既规避了 Apache 对裸 JSON body 的兼容性陷阱,又保持了向后兼容性与调试便利性 —— 这是 Zend Server 等企业级 PHP 环境中处理大体积 JSON POST 的稳健实践。










