如何让 Go 的 HTTP 请求绕过网站的反爬与防火墙检测

2026-02-01 00:00:00 作者:碧海醫心

本文介绍如何通过模拟真实浏览器请求头、启用连接复用等手段,使 go 编写的链接健康检查程序不被 f5 等 web 应用防火墙(waf)拦截或拒绝,从而稳定获取目标网页状态码。

现代 Web 应用防火墙(如 F5 ASM、Cloudflare、AWS WAF)常基于请求特征进行机器人识别——不仅检查 User-Agent,还会分析请求头完整性、顺序、HTTP/1.1 行为(如 Connection: keep-alive)、Accept 与 Accept-Language 等字段是否存在及取值合理性。Go 标准库 net/http 默认发送极简请求,缺少关键浏览器头部,极易被标记为自动化工具并拦截。

要让 Go 请求“看起来像浏览器”,需主动补全以下核心请求头(以 Chrome 最新桌面版为例):

req.Head

er.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36") req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7") req.Header.Set("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7") req.Header.Set("Accept-Encoding", "gzip, deflate") req.Header.Set("Connection", "keep-alive") req.Header.Set("Upgrade-Insecure-Requests", "1") req.Header.Set("Sec-Fetch-Dest", "document") req.Header.Set("Sec-Fetch-Mode", "navigate") req.Header.Set("Sec-Fetch-Site", "none") req.Header.Set("Sec-Fetch-User", "?1")
✅ 重要提示:Sec-* 头部(如 Sec-Fetch-*)虽非 HTTP 标准,但已被主流浏览器广泛采用,F5 等 WAF 常将其作为关键指纹。务必添加(即使 Go 不校验其语义)。

此外,还需优化客户端配置以增强真实性:

  • 启用连接复用:设置 Transport 并复用 TCP 连接;
  • 禁用自动重定向(避免暴露重试行为);
  • 设置合理超时(避免因慢响应触发速率限制);
  • 可选:使用 http.Transport 配置 TLS 指纹(如通过 github.com/zmap/zcrypto/tls 或 github.com/saucelabs/utls 实现 JA3 模拟,进阶场景)。

完整改进版函数示例如下:

func fetchURL(urlStr string, timeout time.Duration) (int, error) {
    client := &http.Client{
        Timeout: timeout,
        Transport: &http.Transport{
            // 复用连接,模拟浏览器持久化连接行为
            MaxIdleConns:        100,
            MaxIdleConnsPerHost: 100,
            IdleConnTimeout:     30 * time.Second,
        },
    }

    req, err := http.NewRequest("GET", urlStr, nil)
    if err != nil {
        return 0, fmt.Errorf("failed to create request: %w", err)
    }

    // 模拟真实浏览器头部(请根据实际测试环境微调)
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
    req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
    req.Header.Set("Accept-Language", "en-US,en;q=0.9")
    req.Header.Set("Accept-Encoding", "gzip, deflate")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("Upgrade-Insecure-Requests", "1")
    req.Header.Set("Sec-Fetch-Dest", "document")
    req.Header.Set("Sec-Fetch-Mode", "navigate")
    req.Header.Set("Sec-Fetch-Site", "none")
    req.Header.Set("Sec-Fetch-User", "?1")

    resp, err := client.Do(req)
    if err != nil {
        return 0, fmt.Errorf("request failed: %w", err)
    }
    defer resp.Body.Close() // 注意:defer 在函数返回前执行,确保资源释放

    return resp.StatusCode, nil
}

⚠️ 注意事项

  • 不要硬编码固定 User-Agent 并长期使用——部分 WAF 会建立 UA 黑名单。建议轮换 2~3 个主流 UA 字符串(Chrome/Firefox/Safari),配合随机延迟(如 time.Sleep(100*time.Millisecond + time.Duration(rand.Intn(200))*time.Millisecond))。
  • 若仍被拦截,可抓包对比浏览器真实请求(Chrome DevTools → Network → Copy as cURL),逐项比对缺失头字段。
  • 对于高防护站点(如银行、政府网站),可能需引入无头浏览器(Puppeteer/Playwright)或代理池,但会显著增加运维复杂度。

总之,“像浏览器” ≠ 仅改 UA,而是系统性地匹配 HTTP 协议层的行为指纹。从请求头完整性、连接策略到 TLS 握手特征,每一步都可能是 WAF 的判断依据。精准模拟,方能稳定通行。

猜你喜欢

联络方式:

400 9058 355

邮箱:8955556@qq.com

Q Q:8955556

微信二维码
在线咨询 拨打电话

电话

400 9058 355

微信二维码

微信二维码