代码之家  ›  专栏  ›  技术社区  ›  Randy Hall

Cloudfront Lambda@edge根据查看器请求设置cookie

  •  0
  • Randy Hall  · 技术社区  · 5 年前

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

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

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

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

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

    有人做过这样的事吗?

    我正在尝试的事情

    我正在研究几个角度,但还没能开始工作:

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

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

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

    Tobin's


    有点工作概念

    1. 查看器请求Lambda在请求对象的头上的cookies中设置UUID。传入了更新的请求对象的回调
    2. 存在UUID cookie busts Cloudfront缓存
    3. 源请求Lambda通过 http.get 设置了UUID cookie(限制为40KB使在查看器请求Lambda中执行此操作不切实际)
    4. 查看者请求Lambda的第二个场景,看到UUID现在存在,剥离UUID cookie,然后正常继续请求
    5. 如果还没有缓存,则返回第二个原始请求-如果缓存了,则返回缓存响应,因为不存在破坏缓存的UUID-将实际页面HTML返回到第一个原始请求
    6. 第一个原始请求接收来自 包含HTML
    7. http.get获取 并用原始的UUID设置Cookie头集

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

    我说“有点”是因为当我试图到达我的端点时,我会下载一个二进制文件。

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


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

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

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

    1 回复  |  直到 5 年前
        1
  •  3
  •   Michael - sqlbot    5 年前

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

    但如果坚持不这样做,那么可以使用Viewer请求触发器将cookie注入请求,然后发出 设置Cookie 在查看器响应触发器中使用相同的值。

    请求 响应 事件,可以在原始文件中找到它的同一位置找到 事件, event.Records[0].cf.request .

    在查看器响应触发器中,结构的这一部分包含 "request that CloudFront received from the viewer and that might have been modified by the Lambda function that was triggered by a viewer request event."

    注意确保正确处理cookie头。这个 Cookie request header 需要小心和准确的操作,因为浏览器 can use multiple formats

    从前,cookies需要作为单个请求头发送。

    Cookie: foo=bar; buzz=fizz
    

    ; 然后 <space> .

    Cookie: foo=bar
    Cookie: buzz=fizz
    

    在后一种情况下,数组 event.Records[0].cf.request.headers.cookie 将包含多个成员。你需要检查 value


    另外:我写了一个函数,我相信它能正确处理所有的情况,包括没有cookie的情况。它将提取您正在查找的名称的cookie。 Cookie names are case-sensitive .

    // 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;
    
    }
    
        2
  •  1
  •   Tobin    5 年前

    您是否可以添加另一个目录:在第一个cookie setter请求中,返回(从lambda)一个重定向,该重定向包括cookie set头,该重定向指向您的实际内容?

    • 从传入请求获取cookie指令
    • 把这个放在某处(缓存等)
    • 在响应上,如果需要,还调用一个函数来读取(缓存)并在响应上设置set cookie头?