S3 存储桶有 2 个面向公众的接口,REST 和网站。这就是两个主机名之间的差异,以及您所看到的行为差异。
它们有两个不同的功能集。
feature REST Endpoint Website Endpoint
---------------- ------------------- -------------------
Access control yes no, public content only
Error messages XML HTML
Redirection no yes, bucket, rule, and object-level
Request types all supported GET and HEAD only
Root of bucket lists keys returns index document
SSL yes no
来源:http ://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html
因此,从表中可以看出,REST 端点支持签名 URL,但不支持友好错误,而网站端点支持友好错误,但不支持签名 URL。两者不能混合和匹配,因此您尝试做的事情并不是 S3 本身支持的。
我通过在 EC2 实例上通过 HAProxy 将存储桶的所有请求传递到存储桶的 REST 端点,解决了这个限制。
当返回 403 错误消息时,代理使用新的嵌入式 Lua 解释器修改响应正文 XML ,将其添加到<Error>
标记之前。
<?xml-stylesheet type="text/xsl" href="/error.xsl"?>\n
该文件/error.xsl
是公开可读的,并使用浏览器端 XSLT 呈现漂亮的错误响应。
代理还将几个附加标签注入到 xml 中,<ProxyTime>
并<ProxyHTTPCode>
在输出中使用。生成的 XML 如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/error.xsl"?>
<Error><ProxyTime>2015-10-13T17:36:01Z</ProxyTime><ProxyHTTPCode>403</ProxyHTTPCode><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>9D3E05D20C1BD6AC</RequestId><HostId>WvdkvIRIDMjfa/1Oi3DGVOTR0hABCDEFGHIJKLMNOPQRSTUVWXYZ+B8thZahg7W/I/ExAmPlEAQ=</HostId></Error>
然后,我使用 XSL 测试改变向用户显示的输出,以确定 S3 抛出了什么错误条件:
<xsl:if test="//Code = 'AccessDenied'">
<p>It seems we may have provided you with a link to a resource to which you do not have access, or a resource which does not exist, or that our internal security mechanisms were unable to reach consensus on your authorization to view it.</p>
</xsl:if>
最终结果如下所示:
以上是一般的“拒绝访问”,因为没有提供凭据。这是过期签名的示例。
我没有HostId
在输出中包含它,因为它丑陋且嘈杂,而且,如果我需要它,代理会为我捕获并记录它,我可以交叉引用请求 ID。
当然,作为奖励,通过我的代理运行请求意味着我可以在提供存储桶内容时使用我自己的域名和我自己的 SSL 证书,并且我有实时访问日志,没有延迟。当代理与存储桶位于同一区域时,额外的数据传输步骤不会产生额外费用,我对这种设置非常满意。