AWS CloudFront - 转发 User-Agent 但不对其进行缓存

AWS CloudFront - forward User-Agent but don't cache against it

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

在“行为”选项卡中,我可以将 User-Agent header 列入白名单,因此它可以正确传递到源,但是现在 CloudFront 缓存每个 User-Agent 的内容,这意味着访问 CloudFront 端点的用户来自不同浏览器的请求会强制 CloudFront 转到源。

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

编辑: Accept-Language header 也有类似的问题。我想将它传递给原点,但我不想对其进行缓存。我正在缓存的资产不依赖于语言,但是 non-cachable 内容依赖于 Accept-Language header.

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

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

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

You can configure CloudFront to cache objects based on values in the Date and User-Agent headers, but we don't recommend it. These headers have a lot of possible values, and caching based on their values would cause CloudFront to forward significantly more requests to your origin.

参考: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);
};

如果请求缓存在不同的 user-agents 中,万一命中,real-user 代理根本不会传递到源。 CloudFront 只会 return 缓存的响应。

您提到您喜欢将 user-agent 信息发送到 Elasticsearch。除非您只对错过的请求感兴趣,否则您不能依赖从源应用程序收集的日志。

如果您让 Lambda@Edge 将 user-agent 作为 realUserAgent 发送,但 user-agent header 本身不是缓存参数,源端仍然不会收到Miss.

情况下的数据

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

这可能是一个简单的解决方案。如果您想要 User-Agent 用于独特类型的 URL 示例,/tracking/a、/tracking/b 会为此路径创建一个新分发 [tracking*] 并将 User-Agent 仅用于此分发。因此,您不会将 AWS 缓存用于所有 url,而只是用于此路径。

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

TLDR:

Over time, we’ve seen numerous cases in which the new functionality could be useful for customers. Examples such as:

  • Forwarding information such as the User-Agent to the origin for analytics/logging but without serving different content variants based on device type (now you can forward the user-agent header and exclude it from the cache-key)

^ 这是您的用例:)