API Gateway をクロスドメインに対応する

has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. AWS

やりたい事は Amazon S3 に HTMLファイルを置いて、jQuery の ajax を使って API Gateway 経由で Lambda の実行結果を取得したい。

普通に実装すると クロスドメイン で怒られます。何故かと言うと、S3 のHTMLファイルと API Gateway のドメインが違うから。同じAWS内だから問題なさそうだけど、駄目みたいです。

クロスドメイン未対応

クロスドメインを考慮しないで実装してみます。

Lambda

要の Lambda関数 から作っていきます。まず、サービスメニューからコンピューティングの Lambda を選択し「関数の作成」を選択します。

Lambda を選択し「関数の作成」を選択

簡単な関数を作るのでとりあえず「一から作成」を選択し、適当な「関数名」を入力て関数を作成します。

「関数名」を入力て関数を作成

Lambda関数 の作成はこれでおしまいです。

API Gateway

次に、呼び出し元(トリガー)を作っていきます。先に作った関数の Designer の「トリガーを追加」を選択します。

Designer の「トリガーを追加」を選択

API Gateway トリガー を選択します。

API Gateway トリガー を選択

API type を「HTTP API」にし、セキュリティを「オープン」にして トリガーを追加します。

API type を「HTTP API」にし、セキュリティを「オープン」にして トリガーを追加

Lambda関数と API Gateway が繋がっていれば、準備完了です。

Lambda関数と API Gateway が繋がる

S3

最後に S3 に呼び出すHTML を置きます。まず、バケットから作成します。

バケットを作成する

一意となるバケット名を入力して「作成」ボタンを押します。

一意となるバケット名を入力

S3 で静的サイトを配信できるように設定を変えます。作ったバケットにチェックを入れて「パブリックアクセス設定を編集する」ボタンを選択します。

「パブリックアクセス設定を編集する」ボタンを選択

5つのチェックを外して「保存」ボタンを押します。

5つのチェックを外して「保存」ボタンを押す

確認と入力し「確認」ボタンを押せば、バケット内の全てのファイルを公開することが出来るようになります。

アクセス欄が「オブジェクトは公開可能」に変わっているのが分かると思います。

オブジェクトは公開可能

公開用バケットが出来たので、次に 静的サイト(HTML)を作ります。ボタンを押したら jQuery の ajax を使って API Gateway 経由で Lambda の実行結果を取得する HTML を作ります。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CrossDomainEx1</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
    <input type="button" value="CrossDomainEx1" onclick="CrossDomainEx1()">
    <div id="CrossDomainEx1"></div>
    <script>
        CrossDomainEx1 = () => {
            $.ajax({
                type: 'GET',
                url: 'https://pxmf09fdqf.execute-api.us-east-2.amazonaws.com/default/CrossDomainEx1'
            }).done((data, textStatus, jqXHR) => {
                // 成功
                $('#CrossDomainEx1').text(data);
            }).fail((jqXHR, textStatus, errorThrown) => {
                // 失敗
                $('#CrossDomainEx1').text(textStatus);
            });
        };
    </script>
</body>
</html>

16行目の url は、自分で作った API Gateway の URL を呼び出すようにします。

API Gateway URL 確認

確認方法は、Lambda関数の Designer の下の API Gateway の APIエンドポイント が 今回のAPIの入り口になります。

APIエンドポイント

作ったHTML を S3 バケットにアップロードします。

S3 バケットにアップロード

「index.html」をドラッグし「アップロード」ボタンでアップロードできます。

「index.html」をドラッグしアップロード

「index.html」を公開設定にします。「index.html」のチェックを入れて アクション をクリックし「公開する」を選択します。

「index.html」のチェックを入れて アクション をクリックし「公開する」を選択

最後に「公開する」ボタンを押すと、ブラウザから見れるようになります。

「公開する」ボタンを押す

公開URLの確認方法

公開URLは「オブジェクトURL」で確認できます。

オブジェクトURL

確認

早速、S3 で公開した 静的サイト(HTML)から、API Gateway 経由で Lambda関数 を実行してみましょう。

その時に F12キー を押して Chrome DevTools を表示しておきます。

has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

ajax を実行した結果 エラー が返ってきました。

has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

Google 翻訳 してみると、

CORSポリシーによってブロックされました:要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。

これが 俗に言うところの、クロスドメインでアクセス拒否されている状態です。

HTML の ドメインが「xxxxx85.s3.us-east-2.amazonaws.com」に対して、API Gateway が「pxmf09fdqf.execute-api.us-east-2.amazonaws.com」なため、CORSポリシーに違反しています。

クロスドメイン対応

CORSポリシーを変更して、クロスドメインでもエラーにならないよう修正します。

API Gateway

CORSポリシーを有効にします。Lambda の Designer から API Gateway を選択し下のリンクから API Gateway の設定画面へ行きます。

Lambda の Designer から API Gateway を選択し下のリンクから API Gateway の設定画面へ

API Gateway の左メニューから「CORS」を選択し、CORSを編集します。

「CORS」を選択し、CORSを編集する

「Access-Control-Allow-Origin」に アクセスを許可するURL を追加します。

どこのサイトからでも使えるようにする場合は「https://*」を追加します。

末尾にスラッシュがあると上手く機能しないので気を付けましょう。

「Access-Control-Allow-Origin」に アクセスを許可するURL を追加

「Access-Control-Allow-Credentials」を有効にして保存したら完了です。

「Access-Control-Allow-Credentials」を有効にして保存

確認

再度、ajax で Lambda関数 からデータを取得出来るか確認します。

Hello from Lambda!

正しく「Hello from Lambda!」が取得出来ました。

おわりに

仕事で AWS を使う機会があり、自分の復習のため 記事にしました。

最初はよく分からずモヤモヤしていたけど、再度自分なりにまとめたら 少しだけですが理解が深まった気がします。

タイトルとURLをコピーしました