本文介绍如何使用CloudFront Functions实现访问跳转。
一、背景
针对特定网站发布的URL跳转需求,例如:
- 访问
/abc/test
,则自动跳转为/abc/test.html
; - 访问
/abc/
,则自动跳转为/abc/index.html
。
以上需求,在CloudFront的图形控制台上操作不能实现。因为CloudFront仅支持到设置根目录的默认页面例如/index.html
的需求,但是不能针对特定子目录设置默认页面。由此可使用CloudFront的边缘算力来提供。关于CDN边缘侧算力Lambda@Edge和CloudFront Functions两个边缘侧计算函数功能的对比,可以参考这篇博客里边有对比表格。
对于访问请求跳转,可通过修改Request请求的URI实现,因此用CloudFront Functions更加轻量级的,是比Lambda@Edge延迟小、且成本更低的方案。CloudFront Functions的计费是每100万次运行收费0.1USD。
下边开始配置。
二、配置和验证访问
1、创建函数
首先进入CloudFront服务的控制台中,点击左侧的Function
函数按钮。点击右上角的创建按钮。如下截图。
在创建函数页面,输入函数的名称,例如取名Redirect
,然后选择版本为cloudfront-js-2.0
。然后点击创建函数按钮。如下截图。
函数创建完成。此时页面下方出现了Build
标签页,这里可输入代码。如下截图。
在Development
的标签页下,粘贴要提交的代码。
function handler(event) {
var request = event.request;
var uri = request.uri;
var clientIP = event.viewer.ip;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri = '/index.html';
console.log({'ClientIP': clientIP});
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '.html';
}
return request;
}
注:以上代码会输出客户端IP地址作为日志,并保存到CloudWatch Log Groups。
点击右上角的Save changes
按钮保存设置。如下截图。
2、测试函数
本文需求有两个,一个是访问任意目录(即请求以/
为结尾),则自动跳转到/index.html
,另一个需求是输入不含扩展名的请求则自动补全.html
扩展名。下边分别测试。
保存成功后,切换到Test
测试标签页,然后在URL Path
位置输入要测试的路径。最后点击右上角的Test function
按钮。如下截图。
将页面向下滚动,可以看到返回的测试结果是成功地跳转到/index.html
,这与预期的一致。如下截图。
接下来测试另一个需求,输入输入不含扩展名的请求,测试是否自动补全。这里在URL Path
位置输入要测试的请求是/abc/myfile
。最后点击右上角的Test function
按钮。如下截图。
将页面向下滚动,可以看到返回的测试结果是成功地跳转到/abc/myfile.html
,这与预期的一致。如下截图。
测试通过后,开始发布。
3、与CloudFront发布点绑定
进入函数的第三个标签页Publish
发布标签页。此时标签页会提示unpublished
未发布字样。点击右下角Publish function
发布函数。如下截图。
函数发布完毕后,向下滚动页面,找到下方Associated distrubtion
绑定发布点位置,点击添加。如下截图。
在下拉框中,选择要绑定的发布点。在请求类型Event type
位置选择Viewer request
,表示来自客户端请求抵达CloudFront时候,运行函数修改请求。在Cache behavior
位置选择默认的Default
。如下截图。
发布成功后,回到函数页面,可以看到当前函数的状态是Updating
更新中。此时CloudFront会在全球的450+边缘节点加载新发布的函数。如下截图。
等待3-5分钟后,发布完成。
4、使用CURL发起测试验证函数运行正常
现在可以使用curl测试了。
首先测试跳转需求1,也就是访问任意的目录跳转到/index.html
。例如请求
curl https://yourname.com/abc01/def02/test1/
此时返回的将是https://yourname.com/index.html
页面的内容。
继续测试跳转需求2,输入不含扩展名的请求则自动补全.html
扩展名。
curl https://yourname.com/abc01/def02/test2
此时返回的将是https://yourname.com/abc01/def02/test2.html
页面的内容。
至此CloudFront Function函数部署完成。
三、CloudFront Function的监控和日志
1、查看函数运行次数
进入CloudFront服务界面,在左侧菜单中,点击Monitoring
菜单。点击右侧标签栏的CloudFront Functions
,在下方的函数清单中,找到要查看的函数选中之,点击右上角的View metrics
按钮。如下截图。
在当前界面下,即可看到函数的运行次数、错误计数等信息。如下截图。
具体的各项监控参数的定义,可参考本文末尾的官方文档。
2、查看CloudFront Functions日志
与Lambda@Edge查看日志的时候要定位用户访问的POP点、以及Regional Cache Center所在地这种方式有所不同,CloudFront Functions查看日志更为简单。CloudFront Functions始终在美国东部(弗吉尼亚北部)区域 (us-east-1) 中创建Cloudwatch日志流,无论用户访问的是哪一个边缘节点。日志组名称的格式为/aws/cloudfront/function/FunctionName
,其中FunctionName
是您在创建函数时为函数指定的名称。日志流名称的格式为YYYY/M/D/UUID
。
需要注意的是,日志输出必须显式的打开。如果CloudFront Functions函数代码包含console.log()
语句,这些日志会发送到CloudWatch Loggroups中。如果代码中没有console.log()
语句,则不会输出日志。本文的Demo代码已经包含了一个日志输出,在进入特定If循环中,会打印日志。
下边开始查看日志。
进入美东1N.Virginia
弗吉尼亚北部区域的的CloudWatch服务,从左侧的菜单中找到Log groups
日志组,点击进入。在右侧的搜索过滤框中,输入关键字Cloudfront
,然后即可列出所有函数的日志组。点击其中一个进入。如下截图。
在日志组界面,点击第一个标签页log streams
。然后下方会列出多条日志流。通过时间戳找到最新的一个,点击进入。如下截图。
在日志中可看到START/END标记,在之间的就是打印日志。本文记录的日志是访问CloudFront的客户端IP地址。如下截图。
至此查看日志完成。
四、小结
本文描述了如何配置一个Cloudfront Functions函数实现对特定URL的跳转。结合使用场景,有如下几点建议:
- 尽量使用CloudFront Functions实现,复杂函数才使用Lambda@Edge实现。因为CloudFront Functions可运行在450+ POP点;而Lambda@Edge只能运行在13个Regional Cache Center,二者网络延迟有差异;
- Cloudfront Functions百万次调用费用$0.1,而Lambda@Edge调用是$0.6,成本差六倍;
- 因为Cloudfront Functions是直接绑定到一整个CDN发布点,因此函数注意测试充分完毕在上线,以免其中的扩展名、目录等逻辑判断错误导致整个发布点故障;
- Cloudfront Functions的测试界面按测试按钮,将不会给CloudWatch Log Groups中打日志;发起测试时候,测试的日子就打在测试页面的下方;
- 函数代码中需要显式用
console.log()
语句打日志,日志统一输出到美东1(us-east-1)弗吉尼亚北部(N.Virginia)区域的CloudWatch Log Groups中,开头为/aws/cloudfront
的就是 - 建议将需要Cloudfront Functions和不需要Cloudfront Functions的内容通过不同的域名,分离到两个发布点;这是因为函数一旦绑定到发布点,本发布点所有的调用都会call这个函数,即便函数中通过
if/else
进行逻辑判断后没有改动访问请求,这样也是会被计为运行次数加1;因此将不需要调用函数的内容通过不同的域名,独立分配到另外的发布点,由此会显著降低函数调用次数。
五、参考文档
CloudFront Functions函数计费
https://aws.amazon.com/cloudfront/pricing/?nc1=h_ls
url-rewrite-single-page-apps
CloudFront Functions 日志
查看默认的 CloudFront Functions 指标
CloudFront Functions 日志