正确做法是禁用 CURLOPT_POST,改用 CURLOPT_CUSTOMREQUEST + 手动构造请求体 + 显式设置 Content-Type;PHP 7.4+ 才支持 stream_context_create 直接指定非标 method;X-HTTP-Method-Override 依赖服务端实现,非标准头。

用 curl_setopt 强制设置非标 HTTP 方法(如 PATCH、PROPFIND)
PHP 的 curl_setopt 默认不支持直接用 CURLOPT_CUSTOMREQUEST 发送非标准 method 的 POST 类请求(比如想发 PATCH 但又需要携带表单数据),因为 CURLOPT_POST 和 CURLOPT_CUSTOMREQUEST 互斥——设了前者,cURL 会强制覆盖 method 为 POST,无视后者。
正确做法是:禁用 CURLOPT_POST,改用 CURLOPT_CUSTOMREQUEST + 手动构造请求体 + 显式设置 Content-Type:
$ch = curl_init('https://api.example.com/item/123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH'); // 关键:不用 CURLOPT_POST
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['name' => 'new name', 'status' => 'active']));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
- 漏掉
Content-Type头会导致服务端解析失败(尤其 Spring Boot、Express 等框架默认只从application/x-www-form-urlencoded或application/json中解析 body) - 如果传的是 JSON,记得用
json_encode()并设Content-Type: application/json,不能混用http_build_query -
CURLOPT_POST必须保持未设置或显式设为false,否则 cURL 内部会重写 method
用 file_get_contents + stream_context_create 实现轻量非标 method
不需要 cURL 扩展时,file_get_contents 配合 stream_context_create 是更轻的替代方案,但它对非标 method 支持有限:PHP 7.4+ 才允许在 method 选项中直接写 PATCH、DELETE 等;旧版本会静默 fallback 到 GET。
实操要点:
立即学习“PHP免费学习笔记(深入)”;
$context = stream_context_create([
'http' => [
'method' => 'PATCH',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['score' => 95]),
'timeout' => 5
]
]);
$response = file_get_contents('https://api.example.com/submit', false, $context);
- PHP 版本低于 7.4 时,
method值若非GET/POST/HEAD,会被忽略,请求实际发出的是GET—— 这个行为不会报错,极易误判 -
content必须是字符串,不能传数组;JSON 数据要提前json_encode,且不能额外加utf8_encode(除非目标接口明确要求 GBK) - 无法设置 cookie、重定向跟随等高级选项,适合简单调用
绕过 method 限制:用 POST + X-HTTP-Method-Override 头
某些 API(如老版 Rails、部分企业网关)接受标准 POST 请求,但通过请求头指定真实 method,比如 X-HTTP-Method-Override: PATCH。这本质是服务端做的 method 重写,客户端无需处理非标 method 兼容问题。
适用场景:
- 目标服务明确文档写了支持
X-HTTP-Method-Override - 你无法控制服务端,但 cURL 又受限于 PHP 环境(如共享主机禁用
CURLOPT_CUSTOMREQUEST) - 需要兼容极旧 PHP 版本(5.6+ 即可)
示例:
$ch = curl_init('https://api.example.com/item/123');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['name' => 'renamed']);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-HTTP-Method-Override: PATCH'
]);
$response = curl_exec($ch);
注意:X-HTTP-Method-Override 不是 HTTP 标准头,是否生效完全取决于服务端实现——没文档确认前,别默认它存在。
常见错误:收到 405 Method Not Allowed 却以为是 PHP 问题
这个状态码 90% 是服务端拒绝该 method,不是 PHP 发送失败。排查顺序必须是:
- 先用
curl -X PATCH -d '...' URL在命令行复现,确认服务端是否真支持 - 检查 PHP 请求中是否误带了多余 header(如
Expect: 100-continue,某些 Nginx 配置下会触发 417) - 抓包看实际发出的请求 method 是什么(
curl_setopt($ch, CURLOPT_VERBOSE, true)可打印底层通信) - 确认服务端路由是否区分大小写(
patch≠PATCH)
最常被忽略的一点:Apache 的 mod_security 或云 WAF(如 Cloudflare、阿里云 WAF)会默认拦截非标 method,即使后端代码完全 OK,请求也到不了你的 PHP 脚本。











