You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP-Curl调用FCM API报411错误,浏览器调用正常问题排查

PHP-Curl调用FCM HTTP v1接口返回411错误的问题解析

我来帮你拆解一下这个问题,你遇到的情况其实是本地请求和服务器端请求的环境差异导致的,而且你复制的请求头完全用错了地方,咱们一步步说:

问题回顾

你用PHP-Curl调用FCM HTTP v1接口推送给主题设备,本地跑脚本一直返回411 Length Required错误,提示需要Content-length头;但把脚本放到主机www目录,通过浏览器访问却能成功。复制浏览器的请求头到Curl里也没用,搞不清Nginx在这里的作用,也不知道代码缺啥配置。

先贴一下你原来的代码方便对照:

$topic = 'xxxxx'; $projectId = 'xxxx'; $title = 'hahaha'; $content = 'lol'; 
$payload = array( 'message' => array( 'topic' => $topic, 'notification' => array( 'title' => $title, 'body' => $content, ) ) ); 
$json = json_encode($payload); 
$headers = array( 
    'Authorization:Bearer '.$this->getFcmApiAccessToken(), 
    'Content-Type: application/json; UTF-8', 
    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 
    'Accept-Encoding: gzip, deflate', 
    'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8', 
    'Cache-Control: max-age=0', 
    'Cookie: hrg_session=30d4sk8ue8jbe795m3aavrgv97ds4n9g', 
    'Host: test.hrgame.com.hk', 
    'Proxy-Connection: keep-alive', 
    'Upgrade-Insecure-Requests: 1', 
    'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36', 
); 
print_r($headers); 
$ch = curl_init(); 
curl_setopt($ch,CURLOPT_URL,"https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send"); 
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 
curl_setopt($ch,CURLOPT_POST, true ); 
curl_setopt($ch,CURLOPT_HEADER, 1); 
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($ch,CURLOPT_POSTFIELDS, $json); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); 
$result = curl_exec($ch); 
curl_close($ch); 
var_dump($result);exit; 

为什么本地和浏览器调用结果不一样?Nginx起了什么作用?

这俩场景的核心差异是请求发起的环境和路径不同:

  • 本地直接跑脚本:是你的PHP-Curl直接向FCM接口发请求,所有请求头、请求体都是你代码里配置的,没有中间层干预。
  • 浏览器访问主机脚本:是浏览器先向你的Nginx服务器发请求,Nginx转发给PHP-FPM执行脚本,脚本里的Curl请求是从Nginx所在的服务器发起的。

Nginx在这里的作用不是直接帮你处理FCM的请求,而是服务器环境的默认配置帮你补全了Curl的正确行为:
服务器端的Curl可能默认开启了自动处理Content-Length的配置,或者PHP-FPM/Nginx的环境变量让Curl能正确计算请求体长度并添加头;而你本地的PHP-Curl环境可能因为某些配置(比如旧版本、自定义的php.ini设置)导致自动添加Content-Length的功能失效,或者你代码里的多余头干扰了这个逻辑。

为什么复制浏览器请求头没用?

你复制的是浏览器发给你自己服务器的请求头,和Curl发给FCM的请求头完全是两回事!比如Cookie、Host: test.hrgame.com.hk、Upgrade-Insecure-Requests这些都是浏览器和你的服务器交互用的,FCM接口根本不需要这些头,你把它们加到Curl里反而会让请求格式混乱,甚至被FCM的服务器判定为无效请求。

你的代码到底缺了什么?怎么修复?

问题主要出在多余请求头干扰和没有让Curl自动处理Content-Length上,修复方法很简单:

修正后的代码

$topic = 'xxxxx'; 
$projectId = 'xxxx'; 
$title = 'hahaha'; 
$content = 'lol'; 

// 构造FCM需要的消息体
$payload = array(
    'message' => array(
        'topic' => $topic,
        'notification' => array(
            'title' => $title,
            'body' => $content,
        )
    )
); 
$json = json_encode($payload);

// 只保留FCM必须的请求头!多余的全部删掉
$headers = array(
    'Authorization: Bearer ' . $this->getFcmApiAccessToken(),
    'Content-Type: application/json; charset=utf-8'
); 

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send");
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 生产环境建议开启SSL验证,测试阶段可以关闭
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);

// 重点:不要手动设置Content-Length!Curl会自动根据POST内容计算并添加
// 除非你确定自己能算对长度,否则绝对不要手动加

$result = curl_exec($ch); 
curl_close($ch); 

var_dump($result);
exit;

额外注意事项

  1. 不要手动设置Content-Length:Curl会自动根据CURLOPT_POSTFIELDS的内容计算长度,手动设置很容易出错(比如忘记算json_encode后的字符串长度,或者编码差异导致长度不对)。
  2. 检查JSON编码是否成功:如果json_encode($payload)返回false,POST内容为空,也会触发411错误,可以用json_last_error()排查编码问题。
  3. 生产环境开启SSL验证:CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST设为false只是测试用,正式环境一定要设为true,避免安全风险。
  4. 确保AccessToken有效:411错误有时候也可能是AccessToken无效导致的间接问题,建议先验证getFcmApiAccessToken()返回的Token是否正确。

内容的提问来源于stack exchange,提问作者dabeige

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:09:12