CloudFront Lambda@Edge HTTPS 重定向
CloudFront Lambda@Edge HTTPS redirect
我有一个 CloudFront 分配,其中一个 Lambda 函数附加到查看器请求挂钩。我正在使用它来重定向到规范域(例如 www.foo.tld -> foo.tld)。我还将分发本身设置为重定向 HTTP -> HTTPS。
问题在于,这需要客户端可能必须执行 2 次请求才能到达正确的 URL。例如:
http://www.foo.tld/ -> https://www.foo.tld/ (performed by CloudFront)
https://www.foo.tld/ -> https://foo.tld/ (performed by Lambda function attached to viewer request hook)
我想在 1 个请求中完成此操作:
http://www.foo.tld/ -> https://foo.tld/
看起来我需要将此功能添加到请求事件中,但 documentation 似乎表明该协议未在请求事件中暴露给 Lambda 函数。
我的问题是:
- 如何将协议公开给附加到查看器请求挂钩的 Lambda 函数?
- 或者,有更好的方法吗?
旁注:重定向改变 both 主机名 and 该方案可能有问题,未来比现在更多,因为浏览器对没有 TLS 的 HTTP 行为的接受度降低。目前,我不知所措,无法引用来源来支持这一点,但我的印象是将 直接 从 http://www.example.com
重定向到 https://example.com
应该避免。不过,如果那是你想要的...
CloudFront 和 Lambda@Edge 支持这一点,但仅在源请求触发器中。
如果您在缓存行为设置中将 CloudFront-Forwarded-Proto
header 列入白名单,您就可以像这样访问该值:
const request = event.Records[0].cf.request; // you may already have this
const scheme = request.headers['cloudfront-forwarded-proto'][0].value;
scheme
的值将是 http
或 https
。
我有点迂腐,所以我喜欢故障保险。此替代版本将始终将 scheme
设置为 https
并避免因任何原因 header 不存在而引发的异常。这可能符合您的口味,也可能不符合您的口味:
const request = event.Records[0].cf.request; // you may already have this
const scheme = (request.headers['cloudfront-forwarded-proto'] || [{ value: 'https' }])[0].value;
这只能在源请求触发器中完成的原因是 CloudFront 实际上不会在内部添加这个 header 直到查看器请求触发器已经触发,如果有的话。
但还要注意,您几乎可以肯定想要在 Origin Request 触发器中执行此操作——因为来自这些触发器的响应可以被缓存……这应该意味着更快的响应和降低成本。将 header 列入白名单还会将其添加到缓存键中,这意味着 CloudFront 将自动缓存任何给定页面的单独 HTTP 和 HTTPS 响应,并且仅针对相同的请求重播它们。
我有一个 CloudFront 分配,其中一个 Lambda 函数附加到查看器请求挂钩。我正在使用它来重定向到规范域(例如 www.foo.tld -> foo.tld)。我还将分发本身设置为重定向 HTTP -> HTTPS。
问题在于,这需要客户端可能必须执行 2 次请求才能到达正确的 URL。例如:
http://www.foo.tld/ -> https://www.foo.tld/ (performed by CloudFront)
https://www.foo.tld/ -> https://foo.tld/ (performed by Lambda function attached to viewer request hook)
我想在 1 个请求中完成此操作:
http://www.foo.tld/ -> https://foo.tld/
看起来我需要将此功能添加到请求事件中,但 documentation 似乎表明该协议未在请求事件中暴露给 Lambda 函数。
我的问题是:
- 如何将协议公开给附加到查看器请求挂钩的 Lambda 函数?
- 或者,有更好的方法吗?
旁注:重定向改变 both 主机名 and 该方案可能有问题,未来比现在更多,因为浏览器对没有 TLS 的 HTTP 行为的接受度降低。目前,我不知所措,无法引用来源来支持这一点,但我的印象是将 直接 从 http://www.example.com
重定向到 https://example.com
应该避免。不过,如果那是你想要的...
CloudFront 和 Lambda@Edge 支持这一点,但仅在源请求触发器中。
如果您在缓存行为设置中将 CloudFront-Forwarded-Proto
header 列入白名单,您就可以像这样访问该值:
const request = event.Records[0].cf.request; // you may already have this
const scheme = request.headers['cloudfront-forwarded-proto'][0].value;
scheme
的值将是 http
或 https
。
我有点迂腐,所以我喜欢故障保险。此替代版本将始终将 scheme
设置为 https
并避免因任何原因 header 不存在而引发的异常。这可能符合您的口味,也可能不符合您的口味:
const request = event.Records[0].cf.request; // you may already have this
const scheme = (request.headers['cloudfront-forwarded-proto'] || [{ value: 'https' }])[0].value;
这只能在源请求触发器中完成的原因是 CloudFront 实际上不会在内部添加这个 header 直到查看器请求触发器已经触发,如果有的话。
但还要注意,您几乎可以肯定想要在 Origin Request 触发器中执行此操作——因为来自这些触发器的响应可以被缓存……这应该意味着更快的响应和降低成本。将 header 列入白名单还会将其添加到缓存键中,这意味着 CloudFront 将自动缓存任何给定页面的单独 HTTP 和 HTTPS 响应,并且仅针对相同的请求重播它们。