PHP cURL 本身不原生支持 HTTP/2,是否支持取决于底层 libcurl 是否编译启用 nghttp2;需通过 curl_version()['features'] & CURL_VERSION_HTTP2 验证,且必须显式设置 CURLOPT_HTTP_VERSION 为 CURL_HTTP_VERSION_2_0 并使用 HTTPS 协议。

PHP cURL 是否原生支持 HTTP/2?
PHP 本身不决定是否支持 HTTP/2,关键看底层 cURL 库(libcurl)的编译选项和版本。PHP 的 curl_setopt() 只是透传配置,能否用 HTTP/2 完全取决于 libcurl 是否启用了 nghttp2(或 h2)支持。
验证方式很简单:
var_dump(curl_version()['features'] & CURL_VERSION_HTTP2);
返回非零值才表示当前 PHP 环境的 cURL 支持 HTTP/2;返回 0 就算你写了 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,请求也会自动降级到 HTTP/1.1。
如何启用并强制使用 HTTP/2 请求
即使 libcurl 支持 HTTP/2,cURL 默认仍走 HTTP/1.1,必须显式指定协议版本,并确保目标服务器支持 ALPN 协商(绝大多数 HTTPS 站点已支持)。
立即学习“PHP免费学习笔记(深入)”;
-
CURLOPT_HTTP_VERSION设为CURL_HTTP_VERSION_2_0(不是字符串"2.0") - 必须使用
https://协议(HTTP/2 over cleartext HTTP/2 不被主流服务端支持) - 推荐加上
CURLOPT_SSL_VERIFYPEER => true和CURLOPT_SSL_VERIFYHOST => 2,避免因证书问题导致协商失败静默降级 - 可选:加
CURLOPT_VERBOSE => true查看实际协商结果(输出里出现* Using HTTP2, server sent HTTP/2才算成功)
示例片段:
$ch = curl_init('https://http2.example.com');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$result = curl_exec($ch);
// 检查错误
if (curl_errno($ch)) {
echo 'cURL error: ' . curl_error($ch);
}
curl_close($ch);常见失败原因与排查要点
HTTP/2 请求失败往往不报错,而是悄悄回退到 HTTP/1.1,很难察觉。重点检查以下几类问题:
- libcurl 版本太低(curl --version 或查
curl_version()输出 - PHP 编译时链接的是旧版系统 cURL,而非自己编译的带 nghttp2 的版本
- 目标域名未开启 HTTP/2(可用
curl -I --http2 https://example.com在命令行验证) - 中间代理或防火墙干扰 ALPN 握手(比如某些企业网络、CDN 配置限制)
- 用了
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2(少个_0),这个常量根本不存在,cURL 会忽略该设置
HTTP/2 带来的实际影响有哪些
对 PHP 后端调用来说,HTTP/2 的优势不是“更快”,而是更稳定地复用连接、减少 TLS 握手开销——尤其在高频小请求场景下。但要注意:
- 单次请求耗时不一定会下降,甚至可能略高(因帧解析开销)
- 并发多个请求时,HTTP/2 的多路复用才能体现价值;若只发一个请求,和 HTTP/1.1 差异极小
- 不支持
curl_multi下的 HTTP/2 多路复用(libcurl 当前限制),每个curl_init()仍是独立连接 - 无法通过 PHP 直接读取 HTTP/2 流优先级、推送流(
PUSH_PROMISE)等特性,这些被 libcurl 屏蔽了
真正需要关注的,是确认协商是否生效,而不是盲目追求 “用了 HTTP/2”。很多线上环境看似配了,实际跑的还是 HTTP/1.1,因为没验证 CURL_VERSION_HTTP2 特征位或没开 VERBOSE 看握手日志。










