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

cURL脚本偶发400错误:排查方法与参数优化咨询

问题与解决方案

我的PHP cURL脚本请求固定URL(symbol参数固定为RWOD)时,时而返回HTTP 200成功,时而返回HTTP 400错误。目标站点访问量高,推测有多台服务器做负载均衡。现需解决两个问题:

  1. 如何获取400错误的详细信息?
  2. 调整哪些cURL参数可让请求稳定成功?

相关信息:

  • 前端页面:https://www.otcmarkets.com/stock/RWOD/profile
  • 实际请求API:https://backend.otcmarkets.com/otcapi/company/profile/full/RWOD?symbol=RWOD
  • 当前cURL代码:
function NewCurl() {
    global
        $OSFLSymb,
        $UseProxy,
        $ProxArr,
        $ProxyAuth,
        $HTTPStatus
    ;
    
    $NewCurlHandle = curl_init();

    $NewUrl = 'https://backend.otcmarkets.com/otcapi/company/profile/full/' . $OSFLSymb . '?symbol=' . $OSFLSymb;
    
    curl_setopt ($NewCurlHandle, CURLOPT_URL, $NewUrl);
    curl_setopt($NewCurlHandle, CURLOPT_SSL_VERIFYPEER,false);

    curl_setopt_array( $NewCurlHandle, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => '',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST  => 'GET',
        CURLOPT_HTTPHEADER     => [
          'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0',
          'Accept: application/json, text/plain, */*',
          'Accept-Language: en-US,en;q=0.5',
          'Origin: https://www.otcmarkets.com',
          'Connection: keep-alive',
          'Referer: https://www.otcmarkets.com/',
          'Sec-Fetch-Dest: empty',
          'Sec-Fetch-Mode: cors',
          'Sec-Fetch-Site: same-site',
          'Cache-Control: max-age=0'
        ],
    ] ); 
    If ($UseProxy) {
        $CurrProxy = $ProxArr[array_rand($ProxArr)];
        curl_setopt($NewCurlHandle, CURLOPT_PROXY, $CurrProxy);
        curl_setopt($NewCurlHandle, CURLOPT_PROXYUSERPWD, $ProxyAuth);
    }
    
    $CurlPageNew = curl_exec( $NewCurlHandle );
    $HTTPStatus = curl_getinfo($NewCurlHandle, CURLINFO_HTTP_CODE);
    echo "<P>HTTP Code: $HTTPStatus"; 
    echo "<BR>Proxy: $CurrProxy";
    $cURLError = curl_error($NewCurlHandle);
    echo "<BR>cURL Error: $cURLError";  
    curl_close($NewCurlHandle);
    return $CurlPageNew;
}

一、获取400错误的详细信息

HTTP 400错误的响应体通常包含具体错误原因(比如参数不合法、请求头格式错误等),你可以通过以下方式捕获:

  1. 输出400状态对应的响应内容
    在获取$HTTPStatus后增加判断逻辑,直接打印响应体:
$HTTPStatus = curl_getinfo($NewCurlHandle, CURLINFO_HTTP_CODE);
echo "<P>HTTP Code: $HTTPStatus"; 
if ($HTTPStatus == 400 && !empty($CurlPageNew)) {
    echo "<BR>400 Error Details: " . htmlspecialchars($CurlPageNew);
}
  1. 查看响应头信息
    部分服务器会在响应头中附加错误提示,可通过curl_getinfo获取:
$responseHeaders = curl_getinfo($NewCurlHandle, CURLINFO_HEADER_OUT);
echo "<BR>Response Headers: " . htmlspecialchars($responseHeaders);

二、调整cURL参数让请求稳定成功

结合负载均衡场景和目标站点的校验逻辑,重点调整以下内容:

1. 修复请求头格式错误

当前代码中User-Agent没有按键: 值的HTTP头格式编写,这是典型的非法请求头,会直接触发400错误。修正后的请求头数组应把User-Agent改为:

'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0'

2. 增加重试机制

负载均衡下部分服务器可能临时过载或触发频率限制,添加重试逻辑可提高成功率:

  • 设置CURLOPT_TIMEOUT为具体数值(比如30秒),避免无限等待
  • 对400/5xx状态码进行1-2次重试,每次间隔1-2秒

3. 对齐真实浏览器请求特征

  • 把Referer改为对应前端页面的完整路径:https://www.otcmarkets.com/stock/' . $OSFLSymb . '/profile,更符合真实访问场景
  • 移除CURLOPT_CUSTOMREQUEST,GET请求使用默认设置即可,手动指定可能引发兼容问题
  • 指定CURLOPT_ENCODING为'gzip, deflate',匹配浏览器的编码协商行为

4. 代理优化

  • 避免每次请求随机切换代理,固定一个代理会话(或同一IP段的代理),降低被识别为爬虫的概率
  • 添加CURLOPT_PROXYTYPE指定代理类型(比如CURLPROXY_HTTP),避免默认值引发的兼容性问题

调整后的完整代码示例

function NewCurl() {
    global
        $OSFLSymb,
        $UseProxy,
        $ProxArr,
        $ProxyAuth,
        $HTTPStatus
    ;
    
    $retryCount = 2; // 最大重试次数
    $retryDelay = 1; // 重试间隔(秒)
    $successResponse = null;

    for ($i = 0; $i <= $retryCount; $i++) {
        $NewCurlHandle = curl_init();
        $NewUrl = 'https://backend.otcmarkets.com/otcapi/company/profile/full/' . $OSFLSymb . '?symbol=' . $OSFLSymb;
        
        curl_setopt ($NewCurlHandle, CURLOPT_URL, $NewUrl);
        curl_setopt($NewCurlHandle, CURLOPT_SSL_VERIFYPEER, false);

        curl_setopt_array( $NewCurlHandle, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING       => 'gzip, deflate',
            CURLOPT_MAXREDIRS      => 10,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
            CURLOPT_HTTPHEADER     => [
              'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0',
              'Accept: application/json, text/plain, */*',
              'Accept-Language: en-US,en;q=0.5',
              'Origin: https://www.otcmarkets.com',
              'Connection: keep-alive',
              'Referer: https://www.otcmarkets.com/stock/' . $OSFLSymb . '/profile',
              'Sec-Fetch-Dest: empty',
              'Sec-Fetch-Mode: cors',
              'Sec-Fetch-Site: same-site',
              'Cache-Control: max-age=0'
            ],
        ] ); 

        if ($UseProxy) {
            // 可选:如需稳定请求,可固定代理而非随机切换
            $CurrProxy = $ProxArr[array_rand($ProxArr)];
            curl_setopt($NewCurlHandle, CURLOPT_PROXY, $CurrProxy);
            curl_setopt($NewCurlHandle, CURLOPT_PROXYUSERPWD, $ProxyAuth);
            curl_setopt($NewCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
        }
        
        $CurlPageNew = curl_exec( $NewCurlHandle );
        $HTTPStatus = curl_getinfo($NewCurlHandle, CURLINFO_HTTP_CODE);
        
        echo "<P>Attempt " . ($i+1) . " - HTTP Code: $HTTPStatus"; 
        if ($HTTPStatus == 400 && !empty($CurlPageNew)) {
            echo "<BR>400 Error Details: " . htmlspecialchars($CurlPageNew);
        }
        echo "<BR>Proxy: " . ($UseProxy ? $CurrProxy : 'None');
        $cURLError = curl_error($NewCurlHandle);
        echo "<BR>cURL Error: $cURLError";  

        if ($HTTPStatus == 200) {
            $successResponse = $CurlPageNew;
            curl_close($NewCurlHandle);
            break;
        }

        curl_close($NewCurlHandle);
        if ($i < $retryCount) {
            sleep($retryDelay);
            echo "<BR>Retrying after $retryDelay seconds...<BR>";
        }
    }

    return $successResponse;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 13:11:04