如何用PHP Curl实现GraphQL请求?解决JSON格式报错问题
PHP Curl调用Cloudflare GraphQL API报错排查与解决
问题场景
用Insomnia测试GraphQL查询完全正常,但改用PHP Curl实现时触发错误,错误信息如下:
failed to recognize JSON request: 'invalid character 'q' looking for beginning of value'
原PHP Curl代码:
$data = array ("query" => "{ viewer { zones(filter: { zoneTag: '" . $zone . "' }) { httpRequestsAdaptive( filter: { datetime_geq: '2023-05-10T08:00:00Z' datetime_lt: '2023-05-10T08:05:00Z' } limit: 10000 orderBy: [ datetime_DESC ] ) { device: clientDeviceType clientIP: clientIP } } } } "); $data = http_build_query($data); $headers = []; $headers[] = 'Content-Type: application/json'; $headers[] = "Authorization: Bearer $token"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/graphql"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $result_plans = curl_exec($ch); $result_plans = json_decode($result_plans, true); curl_close($ch); $response = $result_plans;
错误原因
- 请求格式不匹配:设置了
Content-Type: application/json请求头,但用http_build_query()生成的是URL编码的表单数据(格式类似query=%7Bviewer...),服务端期望JSON格式,解析时直接报错,错误信息里的'q'就是URL编码后query的首字母。 - 查询字符串拼接有风险:原代码直接拼接
$zone变量,容易出现语法错误,也存在注入风险。
修正方案
- 用
json_encode()将请求数据转为标准JSON格式,替代http_build_query() - 改用HEREDOC语法编写GraphQL查询,避免字符串拼接的语法问题,同时提升代码可读性
修正后的代码
// 用HEREDOC编写查询,避免字符串拼接错误 $query = <<<GRAPHQL { viewer { zones(filter: { zoneTag: "$zone" }) { httpRequestsAdaptive( filter: { datetime_geq: "2023-05-10T08:00:00Z" datetime_lt: "2023-05-10T08:05:00Z" } limit: 10000 orderBy: [ datetime_DESC ] ) { device: clientDeviceType clientIP: clientIP } } } } GRAPHQL; // 构造JSON格式的请求体 $data = json_encode(['query' => $query]); $headers = [ 'Content-Type: application/json', "Authorization: Bearer $token" ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/graphql"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 可选:生产环境建议保留SSL验证 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); $result_plans = curl_exec($ch); if (curl_errno($ch)) { // 捕获Curl请求错误 $error_msg = curl_error($ch); die("Curl请求错误: $error_msg"); } $result_plans = json_decode($result_plans, true); curl_close($ch); $response = $result_plans;
额外优化建议
如果查询包含动态参数(比如$zone、时间范围),建议用GraphQL变量传递,进一步避免语法错误和注入风险:
$query = <<<GRAPHQL query GetZoneRequests(\$zoneTag: String!, \$startTime: DateTime!, \$endTime: DateTime!) { viewer { zones(filter: { zoneTag: \$zoneTag }) { httpRequestsAdaptive( filter: { datetime_geq: \$startTime datetime_lt: \$endTime } limit: 10000 orderBy: [datetime_DESC] ) { device: clientDeviceType clientIP: clientIP } } } } GRAPHQL; $data = json_encode([ 'query' => $query, 'variables' => [ 'zoneTag' => $zone, 'startTime' => '2023-05-10T08:00:00Z', 'endTime' => '2023-05-10T08:05:00Z' ] ]);
内容的提问来源于stack exchange,提问作者Sidney Sousa
相关产品推荐
相关产品推荐

