亚马逊AWS官方博客

Lambda@Edge – 在边缘智能地处理 HTTP 请求

去年年底,我宣布推出预览版 Lambda@Edge,并谈论了如何使用它在靠近客户的位置 (低延迟) 智能地处理 HTTP 请求。申请并获得预览版访问权的开发人员一直在很好地使用它,并为我们提供了大量非常有用的反馈意见。在预览期间,我们添加了生成 HTTP 响应和支持 CloudWatch Logs 的功能,并根据反馈意见更新了路线图。

现已正式发布
今天我很高兴地宣布 Lambda@Edge 现已正式发布!您可以使用它来:

  • 检查 Cookie 并重写 URL 以执行 A/B 测试。
  • 根据 User-Agent 标头将特定对象发送给用户。
  • 通过在将请求传递到源之前查找特定标头来实现访问控制。
  • 添加、删除或修改标头以将用户指引到不同的缓存对象。
  • 生成新的 HTTP 响应。
  • 干净利落地支持旧 URL。
  • 修改或缩减标头或 URL 以提高缓存利用率。
  • 向其他 Internet 资源发出 HTTP 请求,并使用结果自定义响应。

Lambda@Edge 允许您创建基于 Web 的丰富且个性化的用户体验。由于它正迅速成为当今世界的常态,因此您不需要配置或管理任何服务器。您可以直接上传代码 (在Node.js 中编写的 Lambda 函数),并选择您为分发版创建的其中一个 CloudFront 行为以及所需的 CloudFront 事件:

在本例中,我的函数 (假设名为 EdgeFunc1) 将会运行,以响应对指定分发版中的 image/* 的源请求。如您所见,您可以运行代码以响应四种不同的 CloudFront 事件:

查看器请求 – 当事件从查看器 (HTTP 客户端,通常是 Web 浏览器或移动应用程序) 到达并且可以访问传入 HTTP 请求时,触发此事件。众所周知,每个 CloudFront 边缘站点都维护一个大型对象缓存,以便它可以高效地响应重复的请求。无论请求的对象是否已被缓存,都会触发此特定事件。

源请求 – 由于所请求的对象未缓存在边缘站点而导致边缘站点反过来要向源发出请求时,触发此事件。它可以访问将向源 (通常是 S3 存储桶或在 EC2 实例上运行的代码) 发出的请求。

源响应 – 在源返回对请求的响应后触发此事件。它能够访问来自源的响应。

查看器响应 – 在边缘站点返回对查看器的响应之前触发此事件。它可以访问此响应。

函数在全局范围内复制,并且请求将自动路由到最佳位置进行执行。您可以编写一次代码,然后无需您执行任何明确的操作,即可以较低延迟向世界各地的用户提供代码。

您的代码可以完全访问请求和响应,包括标头、Cookie、HTTP 方法 (GET、HEAD 等) 和 URI。它可以修改现有标头并插入新标头,但存在一些限制。

操作中的 Lambda@Edge
我们来创建一个为了响应查看器请求事件而运行的简单函数。我打开 Lambda 控制台并创建一个新函数。我选择 Node.js 6.10 运行时并搜索 cloudfront 蓝图:

我选择 cloudfront-response-generation 并配置一个触发器来调用该函数:

Lambda 控制台为我提供了有关我函数的运行环境的一些信息:

我照常输入函数的名称和描述:

蓝图包括一个可正常运行的函数。它生成一个“200”HTTP 响应和一个非常简单的主体:

我将该主体用作我自己代码的起点,以便从请求中提取一些有趣的值,并将它们显示在表中:

'use strict';
exports.handler = (event, context, callback) => {

    /* Set table row style */
    const rs = '"border-bottom:1px solid black;vertical-align:top;"';
    /* Get request */
    const request = event.Records[0].cf.request;
   
    /* Get values from request */ 
    const httpVersion = request.httpVersion;
    const clientIp    = request.clientIp;
    const method      = request.method;
    const uri         = request.uri;
    const headers     = request.headers;
    const host        = headers['host'][0].value;
    const agent       = headers['user-agent'][0].value;
    
    var sreq = JSON.stringify(event.Records[0].cf.request, null, ' ');
    sreq = sreq.replace(/\n/g, '<br/>');

    /* Generate body for response */
    const body = 
     '<html>\n'
     + '<head><title>Hello From Lambda@Edge</title></head>\n'
     + '<body>\n'
     + '<table style="border:1px solid black;background-color:#e0e0e0;border-collapse:collapse;" cellpadding=4 cellspacing=4>\n'
     + '<tr style=' + rs + '><td>Host</td><td>'        + host     + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Agent</td><td>'       + agent    + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Client IP</td><td>'   + clientIp + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Method</td><td>'      + method   + '</td></tr>\n'
     + '<tr style=' + rs + '><td>URI</td><td>'         + uri      + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Raw Request</td><td>' + sreq     + '</td></tr>\n'
     + '</table>\n'
     + '</body>\n'
     + '</html>'

    /* Generate HTTP response */
    const response = {
        status: '200',
        statusDescription: 'HTTP OK',
        httpVersion: httpVersion,
        body: body,
        headers: {
            'vary':          [{key: 'Vary',          value: '*'}],
            'last-modified': [{key: 'Last-Modified', value:'2017-01-13'}]
        },
    };

    callback(null, response);
};

我配置我的处理程序,并请求创建一个具有 Basic Edge Lambda 权限的新 IAM 角色:

在下一页上,我确认我的设置 (就像我对常规 Lambda 函数所做的那样),然后单击 Create function

这将创建函数,将触发器附加到分发版,并且还将启动该函数的全局复制。在复制期间 (通常为 5 至 8 分钟),我的分发版状态将更改为 In Progress

复制完成后,状态立即改回 Deployed

然后,我访问分发版的根 (https://dogy9dy9kvj6w.cloudfront.net/),函数将运行,下面是我看到的样子:

尽管单击图片 (它链接到我的分发版的根) 以运行我的代码!

与往常一样,这是一个非常简单的例子,我相信您可以做得更好。以下是帮助您开始使用的几点提示:

站点管理 – 在维护或灾难恢复操作期间,您可以使用 Lambda@Edge 函数使整个动态网站脱机,并替换关键页面。

大量内容 – 您可以创建记分卡、天气预报或公共安全页面,并快速、经济高效地在边缘提供它们。

创建一些很酷的东西,并在评论或博客文章中分享,我会关注的。

需知信息
当您开始思考如何将 Lambda@Edge 用于您的应用程序时,请记住以下几点:

超时 – 处理源请求和源响应事件的函数必须在 3 秒钟内完成。处理查看器请求和查看器响应事件的函数必须在 1 秒钟内完成。

版本控制 – 在 Lambda 控制台中更新代码后,必须发布新版本并为其设置一组新的触发器,然后等待复制完成。您必须始终使用版本号来引用您的代码;$LATEST 和别名不适用。

标头 – 就像您在我的代码中看到的那样,HTTP 请求标头可作为数组访问。标头分为四类:

  • 可访问 – 可以读取、写入、删除或修改。
  • 受限 – 必须传递给源。
  • 只读 – 可以读取,但不能以任何方式修改。
  • 列入黑名单 – 代码看不到它,并且无法添加。

运行时环境 – 运行时环境为每个函数提供 128 MB 内存,但没有内置库,也无法访问 /tmp

Web 服务访问 – 处理源请求和源响应事件的函数必须在 3 秒钟内完成,并且可以通过 HTTP 访问 AWS API 并获取内容。这些请求总是与对原始请求或响应的请求同步进行。

函数复制 – 如前所述,您的函数将在全局范围内复制。复制副本在 Lambda 控制台的“其他”区域中可见:

CloudFront – 您已经了解的有关 CloudFront 和 CloudFront 行为的一切都与 Lambda@Edge 密切相关。您可以使用每个行为类别中的多个行为 (每个行为最多四个 Lambda@Edge 函数),自定义标头和 Cookie 转发等等。还可以在编辑行为时在事件和函数之间建立关联 (通过包含函数版本的 ARN):

现已推出
Lambda@Edge 现已推出,您可以立即开始使用。定价取决于您的函数被调用的次数及其运行时间的长短 (有关详细信息,请参阅 Lambda@Edge 定价页面)。

Jeff