Cloudfront Lambda@edge 在查看者请求上设置 cookie

Ran*_*all 4 amazon-web-services amazon-cloudfront aws-lambda aws-lambda-edge

更新:更好地收集我的想法

我正在为查看器请求 Lambda 中的每个用户生成一个唯一标识符 (UUID),然后根据该 UUID 选择要返回的缓存页面。这有效。

理想情况下,此用户将始终具有相同的 UUID。

如果该 UUID不存在于该查看器请求的 cookie 中,我必须在该查看器请求中生成该 UUID。我还需要将该 UUID 设置为 cookie,这当然发生在响应而不是请求中。

在没有缓存的情况下,我的服务器只需处理一个自定义标头并在响应标头中创建一个 Set-Cookie。

如果我想缓存页面,我找不到处理这个问题的方法。我可以忽略缓存的请求标头并提供正确的缓存页面,但是用户不会保留该 UUID,因为在他们的下一个请求中没有设置要使用的 cookie。

有没有人完成过这样的事情?

我正在尝试的事情

我正在处理几个角度,但还没有开始工作:

  1. 我不知道 Cloudfront 中的某种设置处理从查看器请求到查看器响应的标头或其他数据传递,这可以在 Cloudfront 中的第二个 lambda 中使用。

  2. 在查看器请求中抢先修改响应对象标头。我认为这是不可能的,因为它们返回的标头尚未创建,除非我缺少一些内置的 Cloudfront 方法。

  3. 某种现有的传递标头,我不知道这是否是一件事,因为我对请求-响应处理的这方面不是很熟悉,但值得一试。

  4. 可能(虽然还没有尝试过)我可以在客户端请求 lambda 中创建整个响应对象,并以某种方式从那里提供缓存页面,修改响应标头,然后将其传递到回调方法中。

托宾的答案实际上有效,但不是一个可靠的解决方案。如果用户没有存储或提供他们的 cookie,它就会变成一个无限循环,而且如果我可以避免它,我宁愿不在我的所有页面前面抛出一个重定向


有点工作的概念

  1. 查看器请求 Lambda,当 cookie 中不存在 UUID 时,生成 UUID
  2. 查看器请求 Lambda 在请求对象标头的 cookie 中设置 UUID。传入更新的请求对象的回调
  3. UUID cookie 的存在破坏了 Cloudfront 缓存
  4. 源请求 Lambda 在存在 UUID 的情况下触发
  5. 源请求 Lambda 通过http.get设置 UUID cookie再次调用原始请求 URL (40KB 限制使得在查看器请求 Lambda 中执行此操作不切实际)
  6. 查看器请求 Lambda 的第二种情况,看到现在存在 UUID,剥离 UUID cookie,然后正常继续请求
  7. 如果尚未缓存,则第二个源请求 - 如果缓存,则缓存响应,因为不存在缓存破坏 UUID - 将实际页面 HTML 返回到第一个源请求
  8. 第一个源请求接收来自http.get包含 HTML 的响应
  9. First Origin Request 创建包含响应正文的自定义响应对象http.get和使用我们原始 UUID 设置的 Set-Cookie 标头

已设置 UUID 的后续调用将从 cookie 中去除 UUID(以防止缓存破坏)并直接跳到查看器请求 Lambda 中的第二个场景,该场景将直接加载页面的缓存版本。

我说“有点”是因为当我尝试访问我的端点时,我下载了一个二进制文件。

编辑

这是因为我没有设置content-type标题。我现在只有一个 302 重定向问题......如果我克服了这个问题,我会发布一个完整的答案。


原始问题

我在查看器请求上有一个函数,它选择一个选项并在从缓存或服务器检索请求之前设置请求中的一些内容。

这有效,但我希望它记住未来用户的选择。这个想法是简单地设置一个cookie,我可以在下次用户通过时读取。由于这是在查看器请求而不是查看器响应上,我还没有想出如何实现这一点,或者甚至可以通过 Lambda 本身实现。

Viewer Request -> 
  Lambda picks options (needs to set cookie) -> 
    gets corresponding content -> 
      returns to Viewer with set-cookie header intact
Run Code Online (Sandbox Code Playgroud)

我已经看到了示例,并且能够通过 Lambda 在查看器响应中成功设置 cookie。这对我没有多大帮助,因为需要根据请求做出决定。毫不奇怪,将此代码添加到 Viewer Request 中,响应中没有显示任何内容。

Mic*_*bot 6

我认为设置不存在的 cookie 的真正正确方法是使用 将 302 重定向返回到相同的 URI Set-Cookie,并让浏览器重做请求。这可能不会产生太大影响,因为浏览器可以重用相同的连接来“跟随”重定向。

但是,如果您坚持不这样做,那么您可以使用 Viewer Request 触发器将 cookie 注入到请求中,然后Set-Cookie在您的 Viewer Response 触发器中发出具有相同值的 cookie 。

请求对象,在观众的反应事件,可以在它在原来发现的同一地点发现的请求事件,event.Records[0].cf.request

在查看器响应触发器中,结构的这一部分包含“CloudFront 从查看器接收的请求,并且可能已被查看器请求事件触发的 Lambda 函数修改。”

请小心确保您正确处理 cookie 标头。该Cookie请求头需要仔细和精确的操作,因为浏览器可以使用多种格式,当多个cookie存在。

曾几何时,cookie 需要作为单个请求标头发送。

Cookie: foo=bar; buzz=fizz
Run Code Online (Sandbox Code Playgroud)

通过拆分;后跟的值来解析这些<space>

但是浏览器也可能将它们拆分为多个标头,如下所示:

Cookie: foo=bar
Cookie: buzz=fizz
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,数组event.Records[0].cf.request.headers.cookie将包含多个成员。您需要检查该value数组中每个对象的属性,检查每个对象中的多个值,并适应这样一个事实,即如果不存在 cookie,则该数组将完全未定义(非空)。


奖励:这是我写的一个函数,我相信它可以正确处理所有情况,包括没有 cookie 的情况。它将使用您要查找的名称提取 cookie。 Cookie 名称区分大小写

Cookie: foo=bar; buzz=fizz
Run Code Online (Sandbox Code Playgroud)