将AWS预签名URL转为Header授权请求(httr2报400错误)
问题分析与修复方案
你的请求构造存在三个核心错误,直接导致了400 Bad Request:
1. Authorization Header格式错误
SignedHeaders字段只能包含header名称(小写),不能附带任何值——你之前把x-amz-date=xxxx这种带值的写法放进去,完全不符合AWS的签名规范。同时要保证SignedHeaders里的header列表,和实际请求中发送的签名header完全一致,顺序也要对应。
2. Credential字符串未解码
原预签名URL里的%2F是斜杠/的URL编码,转成Header授权时必须解码成原始的/,不能保留编码后的%2F,否则AWS无法正确解析凭证信息。
3. 错误处理X-Amz-Expires
X-Amz-Expires是预签名URL的专属参数,不需要作为请求Header发送,也不能出现在SignedHeaders里——它的有效期已经包含在签名逻辑中,直接忽略这个参数即可。
正确的请求构造示例(httr2)
library(httr2) # 从原始预签名URL提取的关键信息 bucket <- "<my-bucket>" file_path <- "<path/to/file.dat>" credential_string <- "<credential-string>" amz_date <- "20241107T202532Z" signature <- "<signature-string>" region <- "us-east-1" # 构造合规的Authorization Header(注意把%2F替换成/) auth_header <- glue::glue( "AWS4-HMAC-SHA256 Credential={credential_string}/{substr(amz_date, 1, 8)}/{region}/s3/aws4_request, ", "SignedHeaders=host;x-amz-date, ", "Signature={signature}" ) # 组装GET请求 req <- request(glue::glue("https://{bucket}.s3.amazonaws.com/{file_path}")) %>% req_headers( `Host` = glue::glue("{bucket}.s3.amazonaws.com"), `X-Amz-Date` = amz_date, `Authorization` = auth_header ) %>% req_perform() # 查看响应结果 resp_body_string(req)
额外验证要点
- 确保SignedHeaders里的header名称全为小写,实际请求header的大小写不影响(AWS会统一转小写处理)。
- 检查
Hostheader的值必须和请求域名完全一致,不能带多余路径或参数。 - 确认
X-Amz-Date的值和预签名URL里的完全相同,修改时间会直接导致签名失效。
内容的提问来源于stack exchange,提问作者mikeck
相关产品推荐
相关产品推荐

