5

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

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

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

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

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

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

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

我正在尝试的事情

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

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

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

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

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

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


有点工作的概念

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

已设置 UUID 的后续调用将从 cookie 中删除 UUID(以防止缓存破坏)并直接跳到 Viewer Request 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

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

4

3 回答 3

7

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

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

查看器响应事件中的请求对象可以在与原始请求事件中找到的位置相同的位置找到。event.Records[0].cf.request

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

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

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

Cookie: foo=bar; buzz=fizz

通过拆分值来解析这些,;然后<space>.

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

Cookie: foo=bar
Cookie: buzz=fizz

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


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

// extract a cookie value from request headers, by cookie name
// const my_cookie_value = extract_cookie(event.Records[0].cf.request.headers,'MYCOOKIENAME');
// returns null if the cookie can't be found
// https://stackoverflow.com/a/55436033/1695906

function extract_cookie(headers, cname) {

    const cookies = headers['cookie'];
    if(!cookies)
    {
        console.log("extract_cookie(): no 'Cookie:' headers in request");
        return null;
    }

    // iterate through each Cookie header in the request, last to first

    for (var n = cookies.length; n--;)
    {
        // examine all values within each header value, last to first

        const cval = cookies[n].value.split(/;\ /);
        const vlen = cval.length;

        for (var m = vlen; m--;)
        {
            const cookie_kv = cval[m].split('=');
            if(cookie_kv[0] === cname)
            {
                return cookie_kv[1];
            }            
        } // for m (each value)    
    } // for n (each header)

    // we have no match if we reach this point
    console.log('extract_cookie(): cookies were found, but the specified cookie is absent');
    return null;

}
于 2019-03-30T22:03:49.683 回答
1

您是否能够添加另一个目录:使用第一个 cookie setter 请求,返回(从 lambda)一个包含 cookie-set 标头的重定向,重定向到您的实际内容?

好的,很长的路要走,但是:

  • 从传入请求中获取 cookie 指令
  • 将此设置在某处(缓存等)
  • 让请求得到你的对象
  • 在响应上,是否还调用一个函数来读取(缓存)并在需要时在响应上设置 set-cookie 标头?
于 2019-03-12T18:52:40.797 回答
0

自问题发布以来已经一年多。我希望您找到了解决方案,并可以与我们分享!

我面临同样的问题,我也在考虑无限循环......这个呢?

  • 查看器请求事件发送回带有 cookie 集的 302 响应,例如,以及在 Location 标头中添加到 URLuuid=whatever 的 GET 参数_uuid_set_=1,例如。

  • 在设置了 GET 参数的下一个查看器请求中_uuid_set_(并且等于 1,但这不是必需的),将有两个选项:

    • 要么uuid未设置 cookie,在这种情况下,您可以发回响应 500 以中断循环,或者任何适合您的需要,

    • 或者设置了 cookie,在这种情况下,您发送另一个 302 并_uuid_set_删除参数,这样最终用户永远不会看到它,也无法复制粘贴和共享,我们都可以在晚上睡觉。

于 2020-10-07T22:01:05.570 回答