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
相关产品推荐
相关产品推荐

