9

我正在尝试在 AWS Cloudfront 上使用 lambda@edge 为多个网站实施“代理”。

我的设置大致是:

DNS:*.domain.com -> some_uuid.cloudfront.net(Cloudfront 分布)

Cloudfront:some_uuid.cloudfront.net -> s3 存储桶来源

s3 存储桶:网站/(包含多个网站的文件夹)

lambda@edge 函数:定义为 origin-request

我的 lambda@edge 函数非常简单:

  1. 检查网站资源是否存在于 s3 存储桶中。

  2. 如果是这样,请将请求 uri 更改为资源 s3 url。

  3. 如果没有,则向后端服务器发送请求以呈现资源,存储在 s3 上并返回它。

我无法获取网站的原始域。例如,如果我尝试访问“my_website.domain.com” - 在我的 lambda 函数中,我没有来自请求的域信息。

我想我可以实现另一个 lambda@edge 函数作为查看器请求以将域作为标头传递,但如果可以的话,我宁愿避免这种情况。

还有其他解决方案吗?

谢谢

4

2 回答 2

15

这里的主要问题是 Cloudfront 覆盖了对源主机的请求中的主机标头。我能够通过结合使用查看器请求 L@E 和源请求 L@E 来解决此问题。

在查看器请求中,L@E 将主机标头复制到另一个标头中,例如 x-forwarded-host。

// viewer-request.js
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request
    request.headers['x-forwarded-host'] = [
      { key: 'X-Forwarded-Host', value: request.headers.host[0].value }
    ]
    return callback(null, request)
}

将您的云端配置为x-forwarded-host将行为中的主机标头列入白名单。这样,Cloudfront 还考虑了x-forwarded-hostwhen 缓存并将标头传递给origin-request lambda.

因此,现在在您的原始请求 lambda 中,您可以访问x-forwarded-host标头

// origin-request.js
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const requestHost = headers['x-forwarded-host'][0].value;
    console.log(requestHost);
    callback(null, request);
}
于 2018-10-29T02:01:51.063 回答
4

因此,您的用例的问题在于,向您的原始请求 L@E 函数公开的主机标头的值是 s3 存储桶的域名,而不是 CloudFront 从查看器收到的原始主机标头,对吗?

为了查看从查看器收到的原始主机标头 CloudFront,您需要将其列入白名单。但是,CloudFront 目前不允许将 s3 源的标头列入白名单。这是 CloudFront 应修复的错误/限制。不过有一个解决方法。如果 s3 存储桶可公开访问(即您没有使用源访问身份),您可以使用诸如 mybucket.s3-website-us-east-1.amazonaws.com 之类的网站端点将您的 S3 源配置为自定义源。然后,您将能够将主机标头列入白名单,并按照查看者的要求查看您网站的域名。然后,您可以根据您的用例修改源请求。不要忘记将主机标头更改回 s3 端点,以便 S3 接受请求。

于 2017-12-15T19:27:27.940 回答