在AWS中,可以通过CloudFront把S3的静态站点作为一个Origin,对外提供服务。这种方式可以提供如下的几点便利:
- 可以通过CloudFront的CDN服务来对静态资源进行加速
- 如果域名通过Route 53解析,那么可以通过aws的Certificate Manager生成一个免费的SSL证书,并且可以到期时自动续期
- 可以通过CloudFront的设置,Policy以及Edge Function等功能实现对request/response的一些定制化功能
在使用CloudFront的过程中,我们发现了一个这样一个问题。
在S3的静态站点设置中,如果访问的地址没有trailing slash,比如 https://exmaple.com/app
,并且在S3的Bucket中存在对应的/app/index.html
,那么S3的静态站点会自动的反馈一个302的response,将/app
重定向到/app/
。而如果请求的地址是带有querystring的,比如https://exmaple.com/app?from=source
,那么在302中,这个querystring会被S3静态站点省略掉,于是最终跳转到的地址就会可能因为缺少必要的参数而不能正常展示或者正常tracking。
在这种情况下,我们利用了CloudFront的edge function机制,对原有request/response进行了判断和修改,在原有的302请求的基础上,增加了对于querystring的传递。
这个function可以在CloudFront的console中直接增加,实现如下:
var querystring = require('querystring');
function transformQuerystring(qs) {
var ret = {};
for(var k in qs) {
var v = qs[k];
if(!!(v.multiValue)) {
ret[k] = Array.map(v.multiValue, function(x) {return x.value;})
}
else {
ret[k] = v.value
}
}
return ret;
}
function handler(event) {
var request = event.request;
var response = event.response;
if(response.statusCode === 302 && !!(response.headers.location) && Object.keys(request.querystring).length > 0) {
response.headers.location.value = response.headers.location.value
+ '?'
+ querystring.stringify(transformQuerystring(request.querystring));
}
return response;
}
注意,这里之所以要搞一个transformQuerystring函数,主要是因为CloudFront的Javascript环境提供了一个querystring模块,可以用于根据querystring的object重建url,但是这个object和传过来的event.request.querystring的结构并不匹配,所以需要转换一下。这个函数需要针对Viewer Response的事件类型做解析,并且在关联distribution时,需要注意Cache Behavior的设置。