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

Python Requests URL编码问题致AWS S3预签名URL请求403错误

解决Requests调用AWS S3预签名URL时的SignatureDoesNotMatch问题

我之前也踩过这个一模一样的坑!问题核心就是requests库会自动对URL进行二次编码,而AWS的预签名URL已经是完全编码好的状态——尤其是你提到的签名部分Bf%2BBufRIxITziSJGuAq9cYFbxBM%3D,被二次编码后会变成Bf%252BBufRIxITziSJGuAq9cYFbxBM%253D,服务器收到的签名和预签名的完全不一致,自然就返回403的SignatureDoesNotMatch了。而且你说的那个config={'encode_uri': False}配置确实已经被移除,没法再用了。

下面给你几个可行的解决方案:

方案一:直接使用urllib3发送请求

绕开requests的自动编码逻辑,直接用底层的urllib3来发起请求,它不会对已经编码好的URL再做额外处理:

import urllib3

# 初始化连接池管理器
http = urllib3.PoolManager()
# 发送PUT请求,直接传入预签名URL和请求体
response = http.request(
    'PUT',
    presigned_url,
    body=your_file_content,  # 替换成你要上传的文件数据
    headers={'Content-Type': 'your/content-type'}  # 按需添加内容类型等头部
)

方案二:手动构造PreparedRequest跳过编码

如果还是想继续用requests库,可以手动构造PreparedRequest,直接指定原始预签名URL,跳过requests的URL编码步骤:

from requests import Request, Session

session = Session()
# 构造基础请求对象
req = Request('PUT', presigned_url)
# 关键:直接使用原始的预签名URL,不让requests自动处理编码
req.url = presigned_url
# 准备请求(此时不会再对URL进行编码)
prepped_request = session.prepare_request(req)
# 设置请求体(比如要上传的文件内容)
prepped_request.body = your_file_content
# 发送请求
response = session.send(prepped_request)

问题根源补充

AWS生成预签名URL时,已经对所有需要编码的字符(包括签名里的+、=)做了正确的URL编码。而requests的默认行为会对整个URL重新编码,把原本的%2B(对应+)再次编码成%252B,导致签名校验彻底失败。之前的encode_uri配置本来是用来关闭这个自动编码的,但后来被移除了,所以只能用上面的方法规避。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:37:08