はじめに
前回、AWS Lambdaを使用したサーバーレス開発について、私がハマった箇所をまとめました。
インフラエンジニアがやってみた AWSでサーバーレス Webアプリケーション開発
そこでCORSについて毎回returnでハマるのでreturnを共通化しました。
文中のAWS LambdaのソースはPython 3.8で書かれています。
言いたいこと
CORSでエラーが出たらLambdaのreturnを疑え。
Why?
JavascriptのコンソールにCORSのエラーが出るとき、十中八九Lambdaで正しくreturnしていないからです。
CORSの仕組みや考え方は以下の参考ページが大変詳しいです。
なんとなく CORS がわかる...はもう終わりにする。
ある程度仕組みを理解して頂いたところで、CORSのエラーが出るパターンは以下になります。
- Lambda側でOPTIONSメソッドに応答していない
- Lambda側で応答していない or 応答している内容に不備がある
かぶっている部分もありますが、大枠でこの2つになると思います。
ポカレベルの内容ですが気づきにくく、結果ハマりました。
returnを共通化する
まず、丁寧にreturnしないといけないので、それなりにreturn部の処理が長くなってしまいます。
なので共通化してreturnできるように2つの関数を作成しました。
# API Gatewayのルールに則った成功の response を生成する
def create_success_response(body, **kwargs):
origin = '*'
methods = 'GET'
for k, v in kwargs.items():
if k == 'origin' : origin = v
if k == 'methods' : methods = v
headers = {
'Access-Control-Allow-Headers' : 'Content-Type',
'Access-Control-Allow-Origin' : origin,
'Access-Control-Allow-Methods' : methods
}
logger.info(
'return values headers = {}, body = {}, origin = {}, methods = {}'
.format(headers, body, origin, methods)
)
return {
'isBase64Encoded': False,
'statusCode' : 200,
'headers' : headers,
'body' : json.dumps(body)
}
# API Gatewayのルールに則った失敗の response を生成する
def create_error_response(body, **kwargs):
origin = '*'
methods = 'GET'
for k, v in kwargs.items():
if k == 'origin' : origin = v
if k == 'methods' : methods = v
headers = {
'Access-Control-Allow-Headers' : 'Content-Type',
'Access-Control-Allow-Origin' : origin,
'Access-Control-Allow-Methods' : methods
}
return {
'isBase64Encoded': False,
'statusCode': 599,
'headers': headers,
'body': json.dumps(body)
}
create_error_response
のほうはstatusCode
を599
でハードコーディングしています。
要件がある場合は、methodsと同じように引数で外部から変更できるようにしてください。
originの内容もサイトのセキュリティポリシーに合わせて、URLを絞ってください。
OPTIONSメソッドに応答していない
LambdaがOPTIONSに対してちゃんと応答しているか疑いましょう。
GET, POST, PUT, DELETE…などなどは応答していたけどOPTIONSを忘れていた、という事があると思います。
というか私がそうでした。
はい、OPTIONSについての処理を追加しましょう。
#=======================================================
# OPTIONS : CORSに必要
#=======================================================
elif event['httpMethod'] == 'OPTIONS':
logger.info('handle the options method.')
return create_success_response(
{ 'message': 'successfully: called options method.' },
methods='GET,PATCH,DELETE'
)
この時大事なのが、methodsにLambdaで受け付けるHTTP Methodをすべて書くことです。
PUT, PATCH, POSTなど細かな違いもちゃんと仕様に合わせて書きましょう。
応答していない or 応答している内容に不備がある
returnを書いてるから応答してる!と思ったら大間違いです!
return時にちゃんと、CORSの仕様に則った応答を返す必要があります。
具体的に言うとcreate_success_response
、create_error_response
関数のheaders
の部分です。
returnを共通化したので、return時に共通化した関数を呼んであげれば大丈夫になりました。
return create_success_response(
response,
methods='GET'
)
どこの処理でもreturn時に関数を呼ぶようにしています。
共通化した関数を経由することで、期待されているレスポンスに適切にフォーマットした後にreturnすることが出来るようにしました。
最後に
適切なフォーマットでreturn出来ていないことが毎回のハマりポイントでした。
returnの処理を共通化することでミスに気づきやすくなりました。
javascript consoleに出力されるCORS errorにさよなら!