ちょっと何を言っているか分からないと思うけど、自分も分かりたくなかった!
ざっくりまとめ
- AWS CloudFrontにはいわゆるエッジコンピューティングを提供する Lambda@Edge がある
- Lambda@Edgeではオリジンから返ってきたbodyの一部を書き換えて返すことは(パパッとは)できない
Lambda@Edgeとは
AWSが提供するCDNサービスCloudFrontに付随する、エッジコンピューティングサービス。配信先のユーザに近いサーバでLambdaを実行して結果を返したら速くコンテンツ提供できるよねーというやつ
ESI (Edge Side Includes) やりたいとか、基本静的コンテンツしか返さないんだけどごく一部で動的にしたいんだよねーでもpathは変えたくないしサーバも用意したくないんだよねーみたいなときに使えそうなやつ
やりたかったこと
CloudFront + S3な構成において、特定のリクエストパラメータが指定された場合にコンテンツの一部を書き換えて配信したい
例えば、S3におっきなjson置いといて ?limit=10&page=1
みたいなクエリパラメータがついていたらjsonの一部だけを返す、みたいな感じ
GET /posts Response: { "posts": [ // たくさんのPost ] }
GET /posts?limit=10&page=1 Response: { "posts": [ // id 1 - 10までのPost ] }
Lambda 関数をトリガーできる CloudFront イベント を呼んで、下記の図でいう Origin Response
をトリガーにLambda@Edgeを動かせばやりたいことできそうだと思うじゃん?
Lambda@Edge 関数の例 とか見てもRequestとResponseそれぞれいじっているようなコードがポコポコ書かれてるし、テンプレートエンジンのレンダリングとかに使えるんじゃねみたいな記事もどこかで見かけたし、絶対行けそうだと思うじゃん????
オリジンから返ってきたbodyはLambda@Edgeで読めない
雑にPoCコード書いてたら、衝撃の事実に気づく
おわかり頂けただろうか?
response headerはしっかり渡ってくるけど、 response bodyは渡ってこない!!! ママ〜!!!!!!!!
いやいやそんなばかなー、と思ってググったら「それ仕様やで」っていうクラメソの記事もヒット
やっぱりそういうことらしいですわ。ぐぬぬー
じゃあどうすんの?
任意のbodyを返すことは出来るので、response bodyが渡って来ないならしょうがないから自分でS3 getするしかない。でも、トリガーが Origin Response
のままだとCFがS3 getしたあと自分でもS3 getする感じになって無駄なので、トリガーを Origin Request
に変えて、
- 所定のパラメータがついていなかったらオリジンにそのまま問い合わせさせる
- 所定のパラメータがついていたら自分でS3 getしてフィルタリング、オリジンに問い合わせさせずにresponseを返す
って感じにするのがスマートかなあ。
もしもっといい方法があったらマジで教えて下さい!
っていうか何でこんな仕様になってるの?教えてエロい人