【问题标题】:AWS CloudFront - forward User-Agent but don't cache against itAWS CloudFront - 转发用户代理但不缓存它
【发布时间】:2019-03-28 14:54:17
【问题描述】:

我希望我的来源能够看到 User-Agent 标头。例如:Gecko/20100101 Firefox/62.0 而不是 Amazon CloudFront

在“行为”选项卡中,我可以将 User-Agent 标头列入白名单,因此它可以正确传递到源,但是现在 CloudFront 会根据 User-Agent 缓存内容,这意味着用户从不同浏览器访问 CloudFront 端点会强制 CloudFront 转到源.

是否有任何方法可以配置 CloudFront 以将一些标头传递给源,但不一定针对它们进行缓存?

编辑: Accept-Language 标头有类似的问题。我想将它传递给原点,但我不想缓存它。我正在缓存的资产不依赖于语言,但不可缓存的内容取决于 Accept-Language 标头。

【问题讨论】:

  • 您两次提到了 CloudFlare,但问题似乎都与 CloudFront 有关。澄清一下?
  • 如果您不针对它进行缓存,那么向源发送标头有什么意义?如果我从其他浏览器访问该站点,则源根本看不到任何内容,因为返回了缓存的内容……但是如果可以接受,则源不需要知道我的用户代理,因为它没有使用它修改响应的信息,它不是用于记录或统计目的,因为无论如何,源端只看到一小部分请求。那么...您实际上要解决什么问题?知道这些信息应该会引导我们找到适当的解决方案。
  • 我的意思是“CloudFront”抱歉,编辑了我的问题。对,所以我的 Web 应用程序具有可缓存的资产、图像、JS、CSS,以及向用户返回个性化数据的不可缓存的 GET 操作。使用类似 CDN 的服务仍然有巨大的好处。在 Kibana 中存储日志时,出于统计原因,我使用 User-Agent。就我而言,我想知道User-Agent,因为它是不影响内容的附加信息。 CloudFront 使其无法实现。也许我的方法并不理想,但这就是这个应用程序的发展方式,我正在寻找实现这一目标的工具。

标签: http amazon-cloudfront user-agent


【解决方案1】:

您可以使用分配给您的 CloudFront 分配的 Lambda@Edge 函数 (https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html)。你需要两个函数:

  1. Viewer-Request 事件处理程序,它将读取 User-Agent 标头并将其复制到例如X-My-User-Agent。在来自客户端的请求到达您的 Cloudfront 分发之前调用 Viewer-Request 处理程序。
  2. Origin-Request 事件处理程序,它将读取X-My-User-Agent 并替换User-Agent。当 Cloudfront 在其缓存中未找到请求的页面并将请求发送到源时,将调用 Origin-Request 处理程序。

请注意,您不应将 User-Agent 添加到 Cloudfront 白名单:

您可以将 CloudFront 配置为根据 Date 和 User-Agent 标头,但我们不推荐它。这些标题 有很多可能的值,并且基于它们的值进行缓存会 导致 CloudFront 将更多请求转发给您的 产地。

参考:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#request-custom-headers-behavior

Viewer-Request 处理程序示例(Lambda@Edge 只能用 NodeJS 或 Python 编写,参考:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-lambda-function-configuration):

'use strict';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const customUserAgentHeaderName = 'X-My-User-Agent';
  const userAgent = headers['user-agent'][0].value;

  headers[customUserAgentHeaderName.toLowerCase()] = [
    {
      key: customUserAgentHeaderName,
      value: userAgent
    }
  ];


  callback(null, request);
};

Origin-Request 处理程序示例:

'use strict';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const customUserAgentHeaderName = 'X-My-User-Agent';
  const realUserAgent = headers[customUserAgentHeaderName.toLowerCase()][0].value;

  headers['user-agent'] = [
    {
      key: 'User-Agent',
      value: realUserAgent
    }
  ];


  callback(null, request);
};

【讨论】:

  • realUserAgent 作为保存值的替代方法是使用字符串化布尔值,即'true''false'。然后将标题从x-my-user-agent 更改为isbot。这样,如果 CloudFront 在其缓存白名单中包含自定义标头,您将仅基于 'true''false' 值进行缓存,并且仍然可以获得高性能缓存。
  • 此外,如果尝试从这些边缘 lambda 记录,请知道“Lambda 在 CloudWatch Logs 区域中创建 CloudWatch Logs 日志流最接近函数执行位置。每个日志流的名称格式为 /aws/lambda/us-east-1.function-name 其中 function-name 是您为功能。因此,请确保在正确的 REGION 中检查 cloudwatch 日志。”取自here
【解决方案2】:

如果请求在不同的用户代理之间缓存,在命中的情况下,真实用户代理根本不会被传递到源端。 CloudFront 只会返回缓存的响应。

您提到您喜欢将用户代理信息发送到 Elasticsearch。除非您只对丢失的请求感兴趣,否则您不能依赖从源应用程序收集的日志。

如果您有 Lambda@Edge 以 realUserAgent 的形式发送用户代理,但用户代理标头本身不是缓存参数,则在 Miss 的情况下,源仍然不会接收该数据。

我在这里看到的唯一解决方案是使用从 CloudFront 生成的访问日志。 CloudFront 访问日志不仅包含用户代理,还包含 IP 地址和其他有用信息。此数据会同时记录 Hit 和 Miss。设置 logstash 以将此信息发送到 Elasticsearch 也很容易。

【讨论】:

    【解决方案3】:

    亚马逊似乎在 2020 年 7 月左右推出了新功能“来源请求政策”。您应该可以使用它(不会在 Lambda@Edge 中陷入困境):https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-cloudfront-announces-cache-and-origin-request-policies/

    TLDR:

    随着时间的推移,我们看到了许多新功能可能对客户有用的案例。例如:

    • 将诸如 User-Agent 之类的信息转发到源以进行分析/记录,但不会根据设备类型提供不同的内容变体(现在您可以转发 user-agent 标头并将其从缓存键中排除)

    ^ 这是你的用例 :)

    【讨论】:

    • 有趣的是,我刚刚阅读了 AWS 上的文档,告诉我这是不可能的,但是转到 Cloudfront 控制台显然是使用(相对)新的 Origin Request Policies。我想说这个答案现在已经成为正确的答案......
    • 也许 AWS 文档落后于他们的新功能 :)
    【解决方案4】:

    这可能是一个简单的解决方案。如果您希望将 User-Agent 用于唯一类型的 URL 示例,/tracking/a,/tracking/b 像这样为此路径 [tracking*] 创建一个新分配,并将此分配的 User-Agent 列入白名单。因此,您不会对所有 url 的 AWS 缓存感到困惑,而只是对这条路径进行缓存。

    【讨论】:

    • 我喜欢这样。似乎比为每个请求运行 Edge lambda 更经济,因为您只需要一个路由的用户代理而不是 API 中的 50 个其他路由。
    猜你喜欢
    • 1970-01-01
    • 2019-05-03
    • 2019-06-14
    • 1970-01-01
    • 2018-06-16
    • 2018-01-22
    • 2021-07-11
    • 2019-02-22
    • 1970-01-01
    相关资源
    最近更新 更多