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

Python请求正常但Golang请求遭Cloudflare拦截问题咨询

问题原因分析

1. Cookie处理差异

Python的requests直接将完整的Cookie字符串写入Cookie请求头,而Golang使用AddCookie方法时,会自动为Cookie添加默认属性(如Path=/、Domain=kick.com),这可能与获取__cf_bm时的原始Cookie属性不符,导致Cloudflare验证失败。

2. 请求头顺序/隐式头缺失

Cloudflare的Bot检测会校验请求头的顺序和完整性:

  • Golang的http库默认按字典序发送请求头,与Python requests的头顺序不一致;
  • Python requests会自动添加部分隐式头(如Accept-Language),而Golang代码中未配置,触发拦截。

3. TLS握手指纹差异

Golang标准库的TLS握手指纹与Chrome浏览器(或Python依赖的urllib3 TLS实现)不同,Cloudflare通过TLS特征识别出这是非浏览器请求,直接拦截。

解决方法

方法一:对齐Cookie与请求头配置

直接模拟Python的请求头构造方式,避免Golang自动修改Cookie属性,同时补全缺失的隐式头:

package main

import (
    "compress/gzip"
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
)

func MakeRequest(url string) (*string, error) {
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        return nil, err
    }

    // 完全对齐Python的请求头,直接设置Cookie字段而非AddCookie
    req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
    req.Header.Set("Accept", "application/json")
    req.Header.Set("Cookie", "__cf_bm=yBP__EtLom8aR55x2yIow3GYMpKSMiAAATdk4xHO7CA-1687137561-0-AbAdr3HpoqE97ImTJi4fWsbDp8iOzl6PBzrSwDnFBoTENSfjb7ZOTVx5YX4fuuUMnrIxzqgyWE+kQlENR3ouM3vkVKSWPljxD/JRJJVGGWFy")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("Accept-Encoding", "gzip, deflate")
    // 补全Python自动添加的隐式头
    req.Header.Set("Accept-Language", "en-US,en;q=0.5")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var reader io.ReadCloser
    reader, err = gzip.NewReader(resp.Body)
    if err != nil {
        // 处理非gzip压缩的情况
        reader = resp.Body
    }
    bytes, err := ioutil.ReadAll(reader)
    if err != nil {
        return nil, err
    }
    body := string(bytes)
    return &body, nil
}

func main() {
    data, err := MakeRequest("https://kick.com/api/v1/channels/xqc")
    if err != nil {
        fmt.Println("请求错误:", err)
        return
    }
    fmt.Println(*data)
}

方法二:自定义请求头顺序(可选)

如果方法一仍无效,可通过手动构造Request的RawHeader来强制指定头顺序,完全匹配Python的请求:

// 在创建req后,替换RawHeader
req.RawHeader = []byte(`User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: application/json
Cookie: __cf_bm=yBP__EtLom8aR55x2yIow3GYMpKSMiAAATdk4xHO7CA-1687137561-0-AbAdr3HpoqE97ImTJi4fWsbDp8iOzl6PBzrSwDnFBoTENSfjb7ZOTVx5YX4fuuUMnrIxzqgyWE+kQlENR3ouM3vkVKSWPljxD/JRJJVGGWFy
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
`)
// 注意:设置RawHeader后,不要用Header.Set修改头,否则会覆盖RawHeader

方法三:模拟浏览器TLS指纹

如果前两种方法都失败,说明Cloudflare通过TLS指纹识别了Golang客户端,可使用utls库模拟Chrome的TLS握手:

// 先安装utls:go get github.com/refraction-networking/utls
package main

import (
    "compress/gzip"
    "fmt"
    "io"
    "io/ioutil"
    "github.com/refraction-networking/utls"
)

func MakeRequest(url string) (*string, error) {
    cfg := &utls.Config{
        ServerName: "kick.com",
    }
    conn, err := utls.Dial("tcp", "kick.com:443", cfg)
    if err != nil {
        return nil, err
    }
    defer conn.Close()

    // 模拟Chrome 114的TLS握手
    err = conn.Handshake()
    if err != nil {
        return nil, err
    }

    // 构造请求体,完全对齐Python的请求
    reqStr := "GET /api/v1/channels/xqc HTTP/1.1\r\n" +
        "Host: kick.com\r\n" +
        "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36\r\n" +
        "Accept: application/json\r\n" +
        "Cookie: __cf_bm=yBP__EtLom8aR55x2yIow3GYMpKSMiAAATdk4xHO7CA-1687137561-0-AbAdr3HpoqE97ImTJi4fWsbDp8iOzl6PBzrSwDnFBoTENSfjb7ZOTVx5YX4fuuUMnrIxzqgyWE+kQlENR3ouM3vkVKSWPljxD/JRJJVGGWFy\r\n" +
        "Connection: keep-alive\r\n" +
        "Accept-Encoding: gzip, deflate\r\n" +
        "Accept-Language: en-US,en;q=0.5\r\n\r\n"

    _, err = conn.Write([]byte(reqStr))
    if err != nil {
        return nil, err
    }

    // 读取响应
    respBuf := make([]byte, 4096)
    n, err := conn.Read(respBuf)
    if err != nil && err != io.EOF {
        return nil, err
    }

    // 处理gzip压缩(需要跳过响应头)
    respStr := string(respBuf[:n])
    bodyStart := len(respStr[:respStr.Index("\r\n\r\n")+4])
    bodyBytes := []byte(respStr[bodyStart:])

    reader, err := gzip.NewReader(io.Reader(bodyBytes))
    if err != nil {
        reader = io.Reader(bodyBytes)
    }
    decompressed, err := ioutil.ReadAll(reader)
    if err != nil {
        return nil, err
    }
    body := string(decompressed)
    return &body, nil
}

func main() {
    data, err := MakeRequest("https://kick.com/api/v1/channels/xqc")
    if err != nil {
        fmt.Println("请求错误:", err)
        return
    }
    fmt.Println(*data)
}
注意事项
  • __cf_bm的有效期仅30分钟,需确保每次请求使用的是最新从浏览器获取的有效Cookie,且User-Agent必须与获取Cookie时完全一致;
  • Cloudflare的Bot检测规则会动态更新,若以上方法失效,需进一步对比浏览器/Python请求的完整数据包(可通过Wireshark或Charles抓包),找出差异点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:44:59