使用requests.get请求HTTP简易服务器返回404,但wget可成功获取
老哥,你遇到的这个情况我之前也碰到过——同一台机器上,wget --no-proxy http://localhost:8000/sample.tar能正常拿到文件,Python的requests库请求同一个URL却返回404,大概率是这几个容易忽略的细节在搞鬼,我给你梳理排查方向:
1. requests默认走了代理,而wget被你强制关了代理
你用wget的时候加了--no-proxy,但requests会默认读取系统的代理配置(比如环境变量里的HTTP_PROXY、HTTPS_PROXY),哪怕是localhost的请求也可能被错误地转发到代理服务器,导致你的本地文件服务器根本没收到请求,自然返回404。
解决办法很简单,在requests.get里显式关闭代理:
def get(url): if url == '': raise ValueError('Empty Fetch URL') try: # 显式禁用所有代理 response = requests.get(url, proxies={"http": None, "https": None}) response.raise_for_status() # 主动抛出HTTP错误,方便排查 return response.content except requests.exceptions.RequestException as e: print(f"请求失败: {e}")
或者你也可以在运行Python脚本前设置环境变量:export NO_PROXY=localhost,127.0.0.1(Linux/macOS),或者set NO_PROXY=localhost,127.0.0.1(Windows),让requests自动跳过本地地址的代理。
2. 代码里的URL存在隐藏的不一致
有时候代码里的URL可能不小心多了空格、换行符,或者大小写差异(虽然HTTP URL通常不区分大小写,但有些简易服务器可能做了严格匹配)。比如你代码里的URL是不是写成了http://localhost:8000/sample.tar (末尾多了空格),或者http://localhost:8000/Sample.tar?
你可以在代码里打印URL的原始格式,对比wget里的地址:
def get(url): if url == '': raise ValueError('Empty Fetch URL') # 用repr()可以显示出隐藏的字符,比如空格、换行 print(f"当前请求的URL: {repr(url)}") try: response = requests.get(url, proxies={"http": None, "https": None}) # ... 后续代码
3. requests的默认请求头被服务器拦截
有些简易HTTP服务器(比如Python自带的python -m http.server)对请求头兼容性很好,但偶尔requests默认的User-Agent或者其他头可能触发了服务器的某种规则(虽然概率很低,但值得排查)。
你可以模拟wget的请求头试试,wget的默认User-Agent格式是Wget/[版本号],你可以用wget --version查看自己的版本,然后在requests里设置:
def get(url): if url == '': raise ValueError('Empty Fetch URL') try: # 模拟wget的请求头 headers = {'User-Agent': 'Wget/1.21.3'} # 换成你的wget版本 response = requests.get(url, headers=headers, proxies={"http": None, "https": None}) response.raise_for_status() return response.content except requests.exceptions.RequestException as e: print(f"请求失败: {e}")
4. 查看服务器访问日志,对比请求差异
如果上面的方法都没用,你可以看看本地HTTP服务器的访问日志(比如Python自带的http.server会在控制台打印每一条请求),对比requests和wget的请求细节:
- 请求路径是否一致?
- HTTP版本是否相同?(requests默认用HTTP/1.1,wget可能用HTTP/1.0)
- 请求方法是不是都是GET?
如果发现是HTTP版本的问题,你可以让requests强制使用HTTP/1.0:
from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager class HTTP10Adapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = PoolManager( num_pools=connections, maxsize=maxsize, block=block, _http_vsn=10, # 设置HTTP版本为1.0 _http_vsn_str='HTTP/1.0' ) def get(url): if url == '': raise ValueError('Empty Fetch URL') try: session = requests.Session() session.mount('http://', HTTP10Adapter()) response = session.get(url, proxies={"http": None, "https": None}) response.raise_for_status() return response.content except requests.exceptions.RequestException as e: print(f"请求失败: {e}")
按这个顺序排查,应该能很快找到问题所在!
内容的提问来源于stack exchange,提问作者hellojoshhhy

