Amazon API Gatewayを利用し、AWS Lambda関数をAPIとして公開する事が出来ますが、公開したAPIをAjaxで利用する場合、Cross-Originでアクセスするケースが出てきます。
※ Cross-Originにしないでアクセスする事もできますが、そちらは後述します。
対応を行う際にいろいろ調べたので、まとめとして書いてみます。
CORSでAPIを利用する
API GatewayリソースのCORSを有効にする
API Gatewayの設定については開発者リファレンスに記載されています。
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors.html
一部引用します
Lambda または HTTP の プロキシ統合の場合、OPTIONS レスポンスヘッダーを API Gateway から設定できます。ただし、プロキシ統合では統合レスポンスが使えないので、Access-Control-Allow-Origin ヘッダーを返すにはバックエンドに依存する必要があります。
1.AjaxでAPI Gatewayを利用するHTMLコンテンツを取得します。
このドメインはAPI Gatewayとドメインが異なるため、APIを利用するとCross-Originになります。
2.preflightリクエストを送信します。
Cross-Originのアクセスになるため、preflightリクエストを送信しますが、preflightリクエストを送るか否かについてブラウザに依存するそうです。(ChromeとIE11で動作が異なる為、少しハマりました)
preflightはOPTIONSでリクエストされ、Mock エンドポイントがレスポンスします。
3.preflightリクエストが成功するとAPIを呼び出します。このレスポンスにもAccess-Control-Allow-Originヘッダーが必要になります。
開発者ガイドに記載されている
Access-Control-Allow-Origin ヘッダーを返すにはバックエンドに依存する必要があります
というのはLambdaの処理(=バックエンド)でレスポンスヘッダーを設定してくださいという解釈をしました。
具体的には以下の実装になります
def respond(err, res=None):
return {
'statusCode': '400' if err else '200',
'body': err if err else json.dumps(res, cls=DecimalEncoder),
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : '*'
},
}
CORSで利用する場合の設定はこれでおしまいです。
CORSを有効にしないでAPIを使う
Access-Control-Allow-Origin : * を設定したくない。また、*の代わりにドメイン指定するのも煩雑だという考えもあると思います。
その場合はCross-Originにならない場所からAPIを利用する事で、CORSを有効にする必要が無くなります。
こんなイメージです。
設定方法としては「HTTP プロキシ統合」が参考になります。
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html
具体的にはLambda関数を公開しているAPIと同じAPIにHTTPプロキシのリソースを作成し、HTMLコンテンツをProxyします。
エンドポイントURLの場所がHTMLコンテンツの置き場です。
注意点としては、APIの直下にhtmlという子リソースを作り、その下にプロキシリソース{proxy+}を作成しています。{proxy+}はパターン一致でProxyするので「html」のリソースを1階層はさまないとreadやwriteのLambda関数に対するリクエストもHTTP Proxyに流れてしまうと考えたからです。
以上の設定を行う事で、Cross-Originにしないで利用できるようになりました。
HTTP ProxyするとHTMLとJSはProxyされるがimageファイルが壊れる?
おまけですが、HTMLコンテンツをHTML Proxyで表示させた際にimageファイルが壊れてしまいました。
※HTTP Statusは200で返りますが、ブラウザで表示できない状態になります。
この事象は「バイナリサポート」を設定することで解消します。(API Gatewayのお作法のようですね)
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-payload-encodings.html