aiohttp异步下载URL返回404错误但同步请求及浏览器访问正常
问题根因
- 核心差异是
aiohttp和requests对已编码URL的处理逻辑不同:你传入的目标URL中已经包含URL编码后的内容(如路径中的EO%3AEUM%3ADAT),requests不会对已编码的URL做二次处理,而aiohttp默认会对URL再次编码,会把百分号%转义为%25,最终请求的路径和原始路径不一致,API网关无法匹配到对应资源,因此返回404。 - 次要可能的原因:部分API网关会拦截
aiohttp默认的User-Agent请求头,拒绝响应。
解决方法
方案1:关闭URL自动编码(推荐,适配当前场景)
修改_get函数,使用yarl.URL构造请求地址并开启encoded=True参数,避免二次编码:
# 先导入yarl的URL类 from yarl import URL async def _get( url: Union[Path, str], timeout: aiohttp.ClientTimeout = aiohttp.ClientTimeout(), **kwargs: Union[aiohttp.BasicAuth, Dict[str, Any]] ) -> bytes: kwargs["timeout"] = timeout # 构造URL时指定encoded=True,保留原始编码不做二次处理 request_url = URL(str(url), encoded=True) async with aiohttp.request("GET", request_url, **kwargs) as response: # 可添加打印验证最终请求地址是否符合预期 # print(f"最终请求地址:{response.url}") return await response.read()
方案2:主动设置请求头
如果修改URL后仍然报错,可以给请求添加和浏览器/requests一致的User-Agent头,避免被网关拦截:
# 调用get函数时传入headers参数 custom_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } get(remote_file, headers=custom_headers)
方案3:拆分查询参数
也可以把URL中的access_token拆分出来作为params参数传入,避免URL编码问题:
# 原始URL去掉query部分 remote_file = 'https://api.eumetsat.int/data/download/collections/EO%3AEUM%3ADAT%3AMSG%3AHRSEVIRI/products/MSG4-SEVI-MSG15-0100-NA-20210916121242.731000000Z-NA' # 单独传token参数 params = {"access_token": "43e1b232-02ed-30db-9d17-363f00a4a1f0"} get(remote_file, params=params)
内容的提问来源于stack exchange,提问作者dl.meteo
相关产品推荐
相关产品推荐

