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

HTTPX请求返回403但requests返回200的原因排查及疑问

问题分析与解决方案

核心差异:默认请求头的不同

requests和httpx的默认请求头存在差异,这才是导致反爬拦截的关键,而非Host头本身——因为HTTP/1.1规范强制要求请求必须包含Host头,requests实际上也会自动添加,只是你可能没在构造请求时看到它显式声明。

比如:

  • requests的默认Accept头通常是*/*
  • httpx的默认Accept头是text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8
  • 两者的Accept-Encoding、Connection等头也存在细微区别

这些差异被站点的反爬机制识别为非标准客户端请求,从而返回403。

解决步骤

  1. 完全复刻requests的请求头
    先捕获requests发送的完整请求头(可通过开启调试日志或打印response.request.headers获取),然后在httpx中完全照搬这些头,禁用httpx的默认头。

示例代码:

import httpx

# 替换为你从requests中捕获到的真实请求头
headers = {
    'User-Agent': '你的目标User-Agent',
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive'
}

# 创建客户端时禁用默认头,手动传入复刻的头
with httpx.Client(headers=headers, default_headers=None) as client:
    response = client.get('目标站点URL')
    print(response.status_code)
  1. 测试移除Host头(不推荐)
    虽然不符合HTTP规范,但可以通过自定义传输适配器移除Host头,仅做测试用(多数服务器会直接拒绝此类请求):
import httpx
from httpx._transports.default import HTTPTransport

class NoHostTransport(HTTPTransport):
    def request(self, request):
        request.headers.pop('Host', None)
        return super().request(request)

with httpx.Client(transport=NoHostTransport()) as client:
    response = client.get('目标站点URL', headers={'User-Agent': '你的User-Agent'})
    print(response.status_code)
  1. 排查其他细节
  • 确认是否存在Cookie差异:requests可能自动处理了站点返回的Cookie,而httpx未同步
  • 验证请求方法、URL(含参数、路径大小写)完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:52:08