首页 > 解决方案 > 使用 AWS Lambda@Edge 设置带有用户位置的浏览器 cookie

问题描述

我有一个从 Cloudfront 加载的 HTML 内容。Cloudfrontcloudfront-viewer-country在他的一些 Lambda@Edge 函数中添加带有用户国家/地区的标头 ( )。我尝试将用户的国家/地区发送到浏览器并使用 JS 代码读取它。

当我添加代码时

response.headers['cloudfront-viewer-country'] = request.headers["cloudfront-viewer-country"];

对于函数origin_reponse,来自 Cloudfront 的响应包含cloudfront-viewer-country带有用户国家/地区的标头,但页面上的 JS 代码无法访问此数据。

我还尝试使用 cookie 将国家/地区发送到浏览器:

let finalCookieArray = [];
const cookiePath = '/';
finalCookieArray.push('cloudfront-viewer-country1='+ countryCode +'; SameSite=Strict; Path=' + cookiePath + '}');    
response['headers']['set-cookie'] = [{
    'key': 'Set-Cookie',
    'value': finalCookieArray
}];

但是这个方法的问题是 Set-Cookie 不能从函数 origin_reponse 中工作。

最后我尝试在函数viewer_reponse中使用上面的代码,但是发送到 this 函数的请求不包含 header cloudfront-viewer-country

有什么方法可以通过 JS 代码(最好只使用 1 个 Lambda@Edge 函数)将 cloudfront 添加的国家发送到浏览器?

标签: amazon-cloudfrontaws-lambda-edge

解决方案


经过一番调查,事实证明OriginResponse Lambda@Edge 函数能够添加将在浏览器中接收的 cookie。

要启用此类行为,必须定义 CloudFront 的分配Forward Cookies = Whitelist / All(取决于您的需要),如果使用白名单,请添加自定义 cookie 名称(我使用的 cookie 从未在我的会话中存在,这将阻止缓存通过 cookie 值并提高缓存的性能)。

CloudFront 分配中的 Cookie 设置

就我而言,我想使用用户所在国家/地区的值设置一个 cookie(由 CloudFront 作为名为 的标头提供cloudfront-viewer-country)。此标头仅在分发的设置设置为基于选定请求标头的缓存=白名单/全部(取决于您的需要)并且如果使用白名单添加标头cloudfront-viewer-country 时可用(如下图所示)

CloudFront 分配中的标头设置

最后,一旦一切准备就绪,使用以下代码创建 Lambda@Edge 函数:

exports.handler = (event, context, callback) => {
    
    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;
    var response = event.Records[0].cf.response;
    
    if (!request)
    {
        callback(null, response);
        return;
    }
    
    var countryCode = "Unknown";
    // Get the user's country from CloudFront's header
    const headers = request.headers;
    if (!!headers &&
        !!headers["cloudfront-viewer-country"] &&
        0 < headers["cloudfront-viewer-country"].length &&
        !!headers["cloudfront-viewer-country"][0].value)
        countryCode = headers["cloudfront-viewer-country"][0].value;
        
    if (!!response)
    {
        let finalCookieArray = [];
        // Save previous set-cookies definitions
        if(!!response['headers'] && !!response['headers']['set-cookie']){
          for(var cookie of response['headers']['set-cookie']){
            finalCookieArray.push(cookie.value);
          }
        }
        
        // Add the country's value as a cookie
        const cookiePath = '/';
        finalCookieArray.push('user_country='+ countryCode +'; SameSite=Strict; Path=' + cookiePath);
        response['headers']['set-cookie'] = [{
            'key': 'Set-Cookie',
            'value': finalCookieArray
        }];
    }
    
    // Return to CloudFront
    callback(null, response);

};

并将函数附加到分布

CloudFront 分布中的 Lambda 函数关联

旁注:由于上述设置将为分发中的所有文件调用 Lambda 函数并可能损害缓存命中,因此您应考虑使用上述设置创建一个新行为(在 CloudFront 的分发中)并将路径模式设置为您要返回该国家/地区的 cookie 的相关文件。


推荐阅读