S3の静的webサイトからのフォームでpdf送信をしてapigatewayに連携をしようとpostリクエストしてもcorsエラーになる

0

●説明 S3[staticwebsite-saekitest]で作成した静的webサイトにndex.htmlに記載したwebフォームにpdfをアップロードしてjavascriptの FormData型を利用してawait fetchによりPOSTをapigatewayに投げている。

しかしjsのコンソールをGoogleChromeの開発モードで確認すると Access-Control-Allow-Originヘッダーが無いのでcorsエラーが起こっていると出てしまう。

APIGateWayの設定は以下の通りで設定後にステージ「test」にデプロイし POSTメソッドの呼び出しURLは https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/test/fileupload となっておりこれをindex.htmlのfetchのURLで設定している (デプロイは設定内容の更新の度に実施している)

●APIの種類 REST API ●リソースの作成 「fileupload」を作成 ●メソッドの作成 ・メソッドタイプ  POST ・統合タイプ  Lambda ・LambdaARN  arn:aws:lambda:ap-northeast-1:471112871639:function:xxxxx ●OPTIONSの設定 ・メソッドレスポンス  Access-Control-Allow-Headers  Access-Control-Allow-Methods  Access-Control-Allow-Origin  を追加 ・統合レスポンス  Access-Control-Allow-Headers 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'  Access-Control-Allow-Methods 'OPTIONS,POST'  Access-Control-Allow-Origin '' ●POSTメソッドの設定 ・メソッドレスポンス  Access-Control-Allow-Origin  を追加 ・統合レスポンス  Access-Control-Allow-Origin '' ●CORSの有効化設定 ・ゲートウェイのレスポンス 未設定 ・Access-Control-Allow-Methods  OPTIONSとPOSTにチェック ・Access-Control-Allow-Headers  Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token ・Access-Control-Allow-Origin  *

●APIのバイナリメディアタイプ multipart/form-data

また、静的webホスティングをしているs3には以下のcors設定を追加している

●s3のcors設定 [ { "AllowedHeaders": [ "Content-Type", "X-Amz-Date", "Authorization", "X-Api-Key", "X-Amz-Security-Token" ], "AllowedMethods": [ "POST" ], "AllowedOrigins": [ "*" ], "ExposeHeaders": [], "MaxAgeSeconds": 3000 } ]

●参考サイト 参考サイト1:https://qiita.com/dnpds-yuharagi/items/e2baffe823777b5421a6 参考サイト2:https://qiita.com/moufuyu/items/340048eef98d98f11187 参考サイト3:https://qiita.com/Occhiii623/items/a66a689b28d2730e0130

●リージョン 東京

●API Gateway のタイプ REST API

追記:20240807 一人目の回答者のおかげでcorsエラーは解決したと思ったのですが 今度は500エラーに苦しまされているため追加でコメントをしたのでご教授願います… →自己解決しましたすみません…

2回答
0
承認された回答

API Gatewayの後ろにあるLambdaのレスポンスでAccess-Control-Allow-Originなどは含んでいますか?
以下のドキュメントに記載されているようなレスポンスを返すようにコードを作成する必要があると思います。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors.html#apigateway-enable-cors-proxy

profile picture
エキスパート
回答済み 2ヶ月前
  • 一応以下のようなコードですがこれではだめでしょうか。

    また、最初のjs側で出ているのでそもそも s3 → apigateway → Lambda の経路を通る場合は、Lambdaコードは今回は関係ないかと思っているのですが違いましたかね…

    import json import boto3 import base64

    s3 = boto3.client('s3')

    def lambda_handler(event, context): try: bucket_name = 'xxxxx' body = event['body'] file_data = base64.b64decode(body['file']) # bodyのファイルをbase64形式へエンコード file_name = 'xxxxx.pdf'

        s3.put_object(
            Bucket=bucket_name,
            Key=file_name,
            Body=file_data,
            ContentType='application/pdf'
        )
        
        return {
            'statusCode': 200,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'OPTIONS,POST',
                'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
            },
            'body': json.dumps('File uploaded successfully')
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'OPTIONS,POST',
                'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
            },
            'body': json.dumps('File upload failed: ' + str(e))
        }
    
  • レスポンスにAccess-Control-Allow-Originが含まれているので問題無いと思います。 設定内容的にも普通にリクエストが成功しそうな気がしています。 https://qiita.com/g_ogawa/items/b10999954788d202e0ff
    ちなみにPostmanやcurlコマンドを使用してAPI Gatewayにアクセスした際にレスポンスヘッダーにAccess-Control-Allow-Originが含まれているか確認できますか? https://qiita.com/takc923/items/1b508bb370c78b7a9d44
    他にも念のための確認ですが、フロントエンド (JavaScript) からリクエストを送っているAPI Gatewayのエンドポイントは正しいですか? エンドポイントが誤っている場合にもCORSエラーが発生します。 https://teratail.com/questions/3f4mwk5iwfwnqh

  • index.htmlの内容は以下の通りです。(<script>にjsを含む)

    Invokeコマンドでも使用したAPIGatewayのPOSTメソッドのURLをそのままコピペで張り付けてます。

    <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>○○</title> </head> <body> <h1>○○</h1> <form id="uploadForm" enctype="multipart/form-data"> <input type="file" id="pdfFile" name="pdfFile" accept="application/pdf" required> <button type="submit">PDFをアップする</button> </form> <script> document.getElementById('uploadForm').addEventListener('submit', async function(event) { event.preventDefault(); const file = document.getElementById('pdfFile').files[0]; const formData = new FormData(); formData.append('file', file);
            try {
                const response = await fetch('https://○○○.execute-api.ap-northeast-1.amazonaws.com/test/fileupload', {
                    method: 'POST',
                    body: formData
                });
                console.log(response);
                if (response.ok) {
                    alert('PDFファイルのアップロードに成功しました!');
                } else {
                    alert('PDFファイルのアップロードに失敗しました');
                }
            } catch (error) {
                alert('Error: ' + error.message);
            }
        });
    </script>
    
    </body> </html>
  • 一応パワーシェルのコマンドですが以下の回答が来まして Access-Control-Allow-Originは含まれているように見えます。

    ●実行コマンド(PowerShell) Invoke-WebRequest -Method Post 'https://○○○.execute-api.ap-northeast-1.amazonaws.com/test/fileupload'

    ●結果 StatusCode : 200 StatusDescription : OK Content : {"statusCode": 500, "headers": {"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "OPTIONS,POST", "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X -A... RawContent : HTTP/1.1 200 OK Connection: keep-alive x-amzn-RequestId: a891c287-729c-4733-8426-01f4a5c96103 Access-Control-Allow-Origin: * x-amz-apigw-id: cB-LFGTMNjMEgXQ= X-Amzn-Trace-Id: Root=1-66b0aa46-5dc3... Forms : {} Headers : {[Connection, keep-alive], [x-amzn-RequestId, a891c287-729c-4733-8426-01f4a5c96103], [Access-Contro l-Allow-Origin, *], [x-amz-apigw-id, cB-LFGTMNjMEgXQ=]...} Images : {} InputFields : {} Links : {} ParsedHtml : mshtml.HTMLDocumentClass RawContentLength : 262

    コマンド結果は以上です。

  • 原因が分かったかもしれません。 API Gatewayはボディサイズが10MBまでしか対応していません。 https://qiita.com/akatsukaha/items/2ba0d709835899dae8dd https://dev.classmethod.jp/articles/tsnote-api-gateway-please-tell-me-why-request_too_large-occurs-on-api-gateway-even-when-the-file-size-is-10-mb-or-less/
    試しにサイズを圧縮したPDFファイルをアップロードしてみました。 サイズが2MBくらいのPDFをアップロードしてみたところLambdaまでリクエストが通るようになりました。 a
    なので、ファイルサイズを小さくするかAPI Gatewayを回避する方法 (具体的には以下のブログで紹介されているようなS3署名付きURLを使用した方法) で対応する必要があります。 https://aws.amazon.com/jp/blogs/news/large-size-files-transferring-by-serverless-s3presignedurl-and-clientside-javascript/

0

~~すみませんが解決したと思ったのですがそうではなかったっぽいので、追加で質問です。 この構成だとどうもcorsエラーは起きないものの 500エラーの(Internal Server Error)が出てしまうのですが もしかするとPOSTメソッドにlambdaプロキシ統合をするのは間違っているのでしょうか。

APIGatewayにLambda呼び出し権限が無いのかな? と思ってPOSTメソッドの統合リクエストにて 以下のポリシーを付与したIAMロールのARNも設定してみたのですがダメでした… (参考:https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/permissions.html)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}

こちらのサイト https://qiita.com/tetsu0831/items/220ba032116dc94063b3 ではlambdaプロキシ統合せずに POSTの統合リクエストにマッピングテンプレートで content-typeにmultipart/form-dataを設定しているので 不安になってきました… しかし、lambdaプロキシ統合のチェックを外すと今度はcorsエラーが再び発生するので どうしたらいいものか…~~

→自己解決しました…  →pdfファイルをlambdaコードが単純に悪かったみたいです

saeki
回答済み 2ヶ月前

ログインしていません。 ログイン 回答を投稿する。

優れた回答とは、質問に明確に答え、建設的なフィードバックを提供し、質問者の専門分野におけるスキルの向上を促すものです。

質問に答えるためのガイドライン

関連するコンテンツ