やったこと
このAWSチュートリアルとこの例を組合せてLambda@Edgeをやってみました。- ヘッダ情報から、ブラウザがデスクトップ、iOS、Androidを判定して、別のhtmlファイルにアクセスする
- 構成は、Browser -> Lambda@Edge -> CloudFront -> S3 (static file)
- 手順はざっくり下記のようになるが、上記リンク先のままでできる
- S3にdesktop, ios, android用のhtmlファイルを入れる
- Cloudfrontでパブリック静的サイトにする
- LambdaEdge対応にする
- TTLの設定が良く解らず、CloudFrontが更新されるまでのタイミングがうまく見極められなかったので時間が無駄になってしまった感あり
CloudFront リクエストとレスポンスを変更するタイミング
以下のようにタイミングを選べますが、今回はオリジンリクエストで、OriginのS3にデータを取りにいくときに、バケットオブジェクトを変えています。最初間違えて(ビューワーリクエストにしてしまっていた)
Lambda@Edge では、Node.js および Python の Lambda 関数を実行して CloudFront が発信するコンテンツをカスタマイズし、ビューワーに近い AWS 地域でこの関数を実行できます。この関数は、プロビジョニングや管理の必要なく、CloudFront イベントに応答を実行します。Lambda 関数を使用して、次の時点で CloudFront リクエストとレスポンスを変更できます。CloudFront がビューワーからリクエストを受信した後 (ビューワーリクエスト)CloudFront がリクエストをオリジンサーバーに転送する前 (オリジンリクエスト)CloudFront がオリジンからレスポンスを受信した後 (オリジンレスポンス)CloudFront がビューワーにレスポンスを転送する前 (ビューワーレスポンス)
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-edge.html
Correct the errors below and try again. Your function's execution role must be assumable by the edgelambda.amazonaws.com service principal.
これはtrusted policy に追加するはずの、edgelambda.amazon.comが入っていなかったのが問題だった。
エラーその2
Lambda@edgeではCWのservice linked roleがいるらしいLog group does not exist The specific log group: /aws/lambda/ does not exist in this account or region
というエラーは結局答えは、
ここ とかにあって、
AWSServiceRoleForCloudFrontLogger の中にあるAWSCloudFrontLoggerと同じポリシーをinlineで書き込むと解決。
https://dev.classmethod.jp/articles/where-is-the-lambda-edge-log/
LambdaExecutionError が出ているのが解った。動作として間違っていなさそうでも、Errorが出ている。Lambda自体に問題もなさそうだが。
解凍は $ gunzip XXX.gz
項目はこのような感じ。
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html
この書き方が便利だった https://stackoverflow.com/questions/13147693/how-to-extract-request-http-headers-from-a-request-using-nodejs-connect
CloudFrontからのHTTP heder requestを無理やり確認するとこうなる。NodeJSのconsole.logでCW logで見ている。
こういうのが出てくる。例えばCloudFront-Is-Mobile-Viewerでモバイルかどうかの判定ができる。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:log-group:/aws/cloudfront/*"
}
]
}
Lambda@EdgeのCWログ
Lambda@Edgeはue-east-1にしか置けないが、ログは実際にLambdaが動作するリージョンにある。 パーミションのエラーと合わせてけっこう嵌っってしまいました。こちらに答え。https://dev.classmethod.jp/articles/where-is-the-lambda-edge-log/
CloudFrontのログ
CloudFrontのコンソールからEnable。S3バケットを設定する。 gzファイルになっているのでダウンロードして見ていた。面倒なのでAthenaとか使えた方がよいのかも。LambdaExecutionError が出ているのが解った。動作として間違っていなさそうでも、Errorが出ている。Lambda自体に問題もなさそうだが。
解凍は $ gunzip XXX.gz
項目はこのような感じ。
#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end
Lambda node.jsでCloudFrontのHTTP headerを出力
User-Agent headerの中を読んでいるらしいが、それが実際どうなっているのかがわからないhttps://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html
この書き方が便利だった https://stackoverflow.com/questions/13147693/how-to-extract-request-http-headers-from-a-request-using-nodejs-connect
# レスポンス
console.log("response:");
console.log(JSON.stringify(response));
# ヘッダー
console.log("request.headers");
console.log(JSON.stringify(request.headers));
# NG: こうやると空白が出力される
console.log(res_headers);
# NG: こうやると objectであることが出力されるだけ
console.log(`headers: "${res_headers}"`);
headers: "[object Object]"
CloudFrontからのHTTP heder requestを無理やり確認するとこうなる。NodeJSのconsole.logでCW logで見ている。
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
console.log(JSON.stringify(request));
callback(null, request);
};
こういうのが出てくる。例えばCloudFront-Is-Mobile-Viewerでモバイルかどうかの判定ができる。
2021-07-11T03:25:31.555Z 51136a8b-d242-4354-b640-5643d8a7eee1 INFO
{
"clientIp": "2001.xxxx...",
"headers": {
"cloudfront-is-mobile-viewer": [
{
"key": "CloudFront-Is-Mobile-Viewer",
"value": "false"
}
],
"cloudfront-is-tablet-viewer": [
{
"key": "CloudFront-Is-Tablet-Viewer",
"value": "false"
}
],
"cloudfront-is-smarttv-viewer": [
{
"key": "CloudFront-Is-SmartTV-Viewer",
"value": "false"
}
],
"cloudfront-is-desktop-viewer": [
{
"key": "CloudFront-Is-Desktop-Viewer",
"value": "true"
}
],
"cloudfront-is-ios-viewer": [
{
"key": "CloudFront-Is-IOS-Viewer",
"value": "false"
}
],
"cloudfront-is-android-viewer": [
{
"key": "CloudFront-Is-Android-Viewer",
"value": "false"
}
],
"x-forwarded-for": [
{
"key": "X-Forwarded-For",
"value": "2001:xxx...."
}
],
"user-agent": [
{
"key": "User-Agent",
"value": "Amazon CloudFront"
}
],
"via": [
{
"key": "Via",
"value": "2.0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.cloudfront.net (CloudFront)"
}
],
"accept-encoding": [
{
"key": "Accept-Encoding",
"value": "gzip"
}
],
"pragma": [
{
"key": "Pragma",
"value": "no-cache"
}
],
"sec-ch-ua": [
{
"key": "sec-ch-ua",
"value": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\", \"Google Chrome\";v=\"90\""
}
],
"sec-ch-ua-mobile": [
{
"key": "sec-ch-ua-mobile",
"value": "?0"
}
],
"sec-fetch-site": [
{
"key": "sec-fetch-site",
"value": "same-origin"
}
],
"sec-fetch-mode": [
{
"key": "sec-fetch-mode",
"value": "no-cors"
}
],
"sec-fetch-dest": [
{
"key": "sec-fetch-dest",
"value": "image"
}
],
"host": [
{
"key": "Host",
"value": "name-of-lambda-edge.s3.region.amazonaws.com"
}
],
"cache-control": [
{
"key": "Cache-Control",
"value": "no-cache"
}
]
},
"method": "GET",
"origin": {
"s3": {
"authMethod": "none",
"customHeaders": {},
"domainName": "name-of-lambda-edge.s3.region.amazonaws.com",
"path": ""
}
},
"querystring": "",
"uri": "/favicon.ico"
}
0 件のコメント:
コメントを投稿