Ошибка CORS CloudFormation API Gateway, доступ к XMLHttpRequest заблокирован

Я пытаюсь использовать CloudFormation для создания шлюза API, но у меня есть проблема с CORS.

Ошибка на фронтенде:

POST https://<>.execute-api.us-east-1.amazonaws.com/prod/<> 500
new:1 Access to XMLHttpRequest at '<>' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • API создается без проблем, и я даже перепроверил каждая страница на консоли с рабочим API и не нашел различий в их Method Request, Integration Request, Integration Response и Method Response для всех методов (включая OPTIONS).
  • Если я удалю ресурсы, созданные шаблоном, и создам их вручную в том же шлюзе API, мой код будет работать так, как ожидалось. Я тестировал локальный хост, внешний код в корзине S3 и PostMan, поэтому могу убедиться, что мой внешний код, лямбда-функции и база данных работают правильно.
  • Я понимаю, что у людей была эта проблема раньше, но я не смог найти ответа, который решил бы мою проблему.

  • Вот мой шаблон.

  • Обратите внимание, что "method.response.header.Access-Control-Allow-Origin": false фактически создает API с теми же настройками, что и рабочий.

  • Я также использую код из файла правильный ответ на этот вопрос.

  • Да, мой запрос OPTIONS имеет заголовок «Access-Control-Allow-Origin».

Обновлять

После ответа dannymac ниже. Я получил это:

  • Я добавил console.info(event.requestContext); в свою лямбда-функцию (написанную на Node.js).
  • Есть журналы для Lambda, когда я тестирую функцию.
2019-06-27T20:07:03.118Z    462b93b2-9d4b-4ed3-bc04-f966fcd034cf    Debug CORS issue. Request ID:
2019-06-27T20:07:03.118Z    462b93b2-9d4b-4ed3-bc04-f966fcd034cf    undefined
  • Вроде нет event.requestContext.
  • Я выбрал Enable CloudWatch Logs-INFO и Enable Detailed CloudWatch Metrics с CloudWatch log role ARN*:arn:aws:iam::<ID>:role/ApiGatewayCloudWatchLogsRole (это роль, созданная AWS) в настройках API Gateway.
  • Однако для CloudWatch журнала API Gateway нет. В журнале по умолчанию CloudWatch - Log Groups: /aws/apigateway/welcome
Time (UTC +00:00)
2019-06-27
19:50:55
Cloudwatch logs enabled for API Gateway
  • Похоже, лог CloudWatch не получил тест от API Gateway.
  • Вот что я получил от тестирования метода GET в моем API Gateway:
Response Body
{
  "message": "Internal server error"
}
Response Headers
{}
Logs
Execution log for request 10d90173-9919-11e9-82e1-dd33dda3b9df
Thu Jun 27 20:20:54 UTC 2019 : Starting execution for request: 10d90173-9919-11e9-82e1-dd33dda3b9df
Thu Jun 27 20:20:54 UTC 2019 : HTTP Method: GET, Resource Path: /notes
Thu Jun 27 20:20:54 UTC 2019 : Method request path: {}
Thu Jun 27 20:20:54 UTC 2019 : Method request query string: {userid=<ID>}
Thu Jun 27 20:20:54 UTC 2019 : Method request headers: {}
Thu Jun 27 20:20:54 UTC 2019 : Method request body before transformations: 
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:770402430649:function:test-api-gateway-2-LambdaFunction-1XDONAN3QIY9I/invocations
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request headers: {x-amzn-lambda-integration-tag=... [TRUNCATED]
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request body after transformations: {"resource":"/notes","path":"/notes","httpMethod":"GET","headers":null,"multiValueHeaders":null,"queryStringParameters":{"userid":"<USERID>"},"multiValueQueryStringParameters":{"userid":["<USERID>"]},"pathParameters":null,"stageVariables":null,"requestContext":{"path":"/notes","accountId":"<ID>"...,"identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"<ARN>","apiKeyId":"test-invoke-api-key-id","userAgent":..."test [TRUNCATED]
Thu Jun 27 20:20:54 UTC 2019 : Sending request to https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<ID>:function:test-api-gateway-2-LambdaFunction-<STRING>/invocations
Thu Jun 27 20:20:54 UTC 2019 : Received response. Status: 403, Integration latency: 6 ms
Thu Jun 27 20:20:54 UTC 2019 : Endpoint response headers: {Date=Thu, 27 Jun 2019 20:20:54 GMT, Content-Length=130, Connection=keep-alive, x-amzn-RequestId=<ID>}
Thu Jun 27 20:20:54 UTC 2019 : Endpoint response body before transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Thu Jun 27 20:20:54 UTC 2019 : Lambda invocation failed with status: 403. Lambda request id: feb22917-0dea-4f91-a274-fb6b85a69121
Thu Jun 27 20:20:54 UTC 2019 : Execution failed due to configuration error: 
Thu Jun 27 20:20:54 UTC 2019 : Method completed with status: 500
  • Я также экспортировал как работающий, так и неработающий API-шлюз в Swagger 2. Единственное отличие:
// working one:
"x-amazon-apigateway-any-method": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "noteid",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "security": [
          {
            "mobile-notes-api-authorizer": []
          }
        ]
      }
// not working one:
"x-amazon-apigateway-any-method": {
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "security": [
          {
            "test-api-gateway-2-authorizer": []
          }
        ]
      }
  • У них обоих есть:
"headers": {
              "Access-Control-Allow-Origin": {
                "type": "string"
              },
              "Access-Control-Allow-Methods": {
                "type": "string"
              },
              "Access-Control-Allow-Headers": {
                "type": "string"
              }
            }
  • Раньше я пытался использовать шаблон Swagger в Body моего шлюза API, но не смог решить проблему с недействительным авторизатором.

Иногда это происходит, когда предварительный запрос OPTIONS не имеет заголовка «Access-Control-Allow-Origin». Вы уже проверили это?

MrJomp 20.06.2019 19:11

Возможно, это будет полезно для вас: stackoverflow.com/questions/40292888/…

Deependra Dangal 21.06.2019 04:38

Спасибо @DeependraDangal, если вы посмотрите на мой шаблон, я использую код из этого исправленного ответа.

Viet 21.06.2019 15:41

(Не беспокойтесь о нечетном отрицательном голосовании здесь. Комментировать это бесполезно, так как анонимный отрицательный голос уже давно ушел. Если необходимо, пишите свои ответы в комментариях, но, пожалуйста, не добавляйте комментарии для голосования к сообщениям - они не представляют интереса для большинства читателей).

halfer 29.06.2019 22:34

Спасибо @halfer, я буду иметь это в виду.

Viet 30.06.2019 04:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
3 087
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Моя лучшая догадка: POST к вашей лямбда-функции ANY происходит сбой во время выполнения, а заголовок Access-Control-Allow-Origin не устанавливает значение * (или ваш домен). Каждый раз, когда я получаю ошибку 5XX и ошибку CORS одновременно из запроса, отличного от OPTIONS, это почти всегда так для меня.

Рекомендуемые следующие шаги: воспроизведите ситуацию с ошибкой после добавления ведения журнала отладки в исходный код Lambda и включения журналов CloudWatch в API-интерфейсе API Gateway Rest. Вы можете сделать это, перейдя в консоль API Gateway, щелкнув Stages > Prod > Logs/Tracing, а затем проверив эти два параметра: Enable CloudWatch Logs (уровень журнала: INFO) и Enable Detailed CloudWatch Metrics. Затем вы должны «развернуть» изменения, чтобы они вступили в силу. Сделайте это, нажав кнопку Actions в меню Resources вашего Rest API и выбрав Deploy API. Я также рекомендую регистрировать extendedRequestId (свойство события, переданное вашему обработчику) из вашей функции Lambda, чтобы связать запрос Lambda с запросом шлюза API: event.requestContext.extendedRequestId.

Примеры журналов шлюза API:

(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Extended Request Id: b5zpBGS3IAMFvqw=
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Verifying Usage Plan for request: b66b3876-984b-11e9-95eb-dd93c7e40ca0. API Key: API Stage: 1234567890/Prod
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) API Key authorized because method 'ANY /forms' does not require API Key. Request will not contribute to throttle or quota limits
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Usage Plan check succeeded for API Key and API Stage 1234567890/Prod
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Starting execution for request: b66b3876-984b-11e9-95eb-dd93c7e40ca0
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) HTTP Method: GET, Resource Path: /forms
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Lambda execution failed with status 200 due to customer function error: select count(*) AS `count(*)` from (select `user`.* from `user` where (id IN ('some_id_123'))) as `temp` - Cannot enqueue Query after fatal error.. Lambda request id: 1ae2bb06-5347-4775-9277-caccc42f18f2
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Method completed with status: 502
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) AWS Integration Endpoint RequestId : 1ae2bb06-5347-4775-9277-caccc42f18f2
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) X-ray Tracing ID : 1-5d13cca0-3be96a1ab93a877edc70577c

Пример коррелированных журналов выполнения Lambda:

START RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2 Version: $LATEST
2019-06-26T19:50:56.391Z  1ae2bb06-5347-4775-9277-caccc42f18f2 { "extendedRequestId": "b5zpBGS3IAMFvqw = ", ... }
2019-06-26T19:50:57.853Z  1ae2bb06-5347-4775-9277-caccc42f18f2 { "errorMessage": "select count(*) AS `count(*)` from (select `user`.* from `user` where (id IN ('some_id_123'))) as `temp` - Cannot enqueue Query after fatal error.", ... }
END RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2
REPORT RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2  Duration: 1660.45 ms  Billed Duration: 1700 ms Memory Size: 256 MB  Max Memory Used: 57 MB  

другие мысли: Экспорт определений Swagger как неработающего API, так и рабочего API. Сравните и посмотрите, что отличается. Сделайте это в консоли, выбрав Stages > Prod > Export > Export as Swagger + API Gateway Extensions. Возможно, это не совсем то же самое, что и шаблон CloudFormation, но очень близко.

Большое спасибо @dannymac! Позвольте мне попробовать то, что вы предложили, и вернуться к вам.

Viet 27.06.2019 01:03

Об экспорте swagger. Я сделал это, а также openAPI, но мне не удалось заставить код swagger или openAPI работать внутри свойства Body объекта AWS::ApiGateway::RestApi из-за проблемы с авторизатором. Я обновлю свой вопрос.

Viet 27.06.2019 01:07

Я сделал то, что вы предложили, но не смог найти проблему. Я обновил свой вопрос выше.

Viet 27.06.2019 22:34
Ответ принят как подходящий

Я разобрался с проблемой. Есть 2 основные вещи:

  1. IntegrationHttpMethod для Lambda должен быть POST. Я нашел ответ здесь.
  2. В шаблоне не было AWS::Lambda::Permission, позволяющего API Gateway вызывать функцию Lambda. С шаблоном, когда вы используете AWS::Lambda::Permission, он будет отображать API как триггер вашей лямбда-функции. Однако если вы вручную создадите шлюз API и свяжете его со своей функцией Lambda, он не будет отображать шлюз API в качестве триггера, но все равно будет работать.

Итак, для шаблона, который я разместил выше, мне нужно было добавить это, чтобы он работал:

"LambdaPermission": {
            "Type": "AWS::Lambda::Permission",
            "Description": "Permission for API GateWay to invoke Lambda.",
            "Properties": {
                "Action": "lambda:invokeFunction",
                "FunctionName": {
                    "Fn::GetAtt": [
                        "LambdaFunction",
                        "Arn"
                    ]
                },
                "Principal": "apigateway.amazonaws.com",
                "SourceArn": {
                    "Fn::Join": [
                        "",
                        [
                            "arn:aws:execute-api:",
                            {
                                "Ref": "AWS::Region"
                            },
                            ":",
                            {
                                "Ref": "AWS::AccountId"
                            },
                            ":",
                            {
                                "Ref": "ApiGateway"
                            },
                            "/*"
                        ]
                    ]
                }
            }
        },

И отредактируйте метод ЛЮБОЙ, чтобы он выглядел так

"methodNotesANY": {
            "Type": "AWS::ApiGateway::Method",
            "DependsOn": "LambdaPermission",
            "Properties": {
                "AuthorizationType": "COGNITO_USER_POOLS",
                "AuthorizerId": {
                    "Ref": "GatewayAuthorizer"
                },
                "RestApiId": {
                    "Ref": "ApiGateway"
                },
                "ResourceId": {
                    "Ref": "resourceNotes"
                },
                "HttpMethod": "ANY",
                "Integration": {
                    "Type": "AWS_PROXY",
                    "IntegrationHttpMethod": "POST",
                    "Uri": {
                        "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"
                    },
                    "IntegrationResponses": [{
                        "StatusCode": "200"
                    }]
                },
                "MethodResponses": [{
                    "ResponseModels": {
                        "application/json": "Empty"
                    },
                    "StatusCode": "200"
                }]
            }
        },

Хотел бы я увидеть ваш ответ раньше ... сэкономил бы мне часы копания ...

its.david 03.01.2022 05:53

Другие вопросы по теме