修复AWS API网关和amplify中的CORS“响应预检查...”头部未出现问题

15

我一直在为下面的错误苦苦挣扎。我尝试了很多教程和stackoverflow答案,但是没有一个解决方案能够解决我的问题。

跨源资源共享(CORS)策略阻止从源 'http://localhost:3000' 访问 'https://xxx' 的XMLHttpRequest。响应预检请求未通过访问控制检查:所请求的资源上不存在“Access-Control-Allow-Origin”头。

我正在使用SAM serverless创建我的api。

template.yaml:

Globals:
  Function:
    Timeout: 10
  Api:
    Cors:
      AllowMethods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
      AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
      AllowOrigin: "'*'"

我的Lambda函数: 我的GET响应和OPTIONS响应都返回以下标头:

headers: {
  "Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
  "Access-Control-Allow-Origin": "'*'",
  "Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
}

使用amplify在我的ReactJs应用程序中获取API:

API.get(apiName, path, {
   headers: {
      "Access-Control-Allow-Origin": "*",
      // "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with",
      // "Access-Control-Allow-Methods": "OPTIONS,POST,GET,PUT,DELETE",
      // 'Content-Type': 'application/json'
   }
})

我已经尝试了在我的template.yaml、lambda函数和reactJs项目中使用的Access-Control-Allow-Headers和Access-Control-Allow-Methods的每种组合。

当我在API端点上调用postman中的选项时,这是我的结果。因此,根据我的理解,我的API允许CORS,并且我确实得到了正确的标头。 enter image description here


如果您在选项请求中省略了 "x-api-key" 标头,会发生什么? - Jannes Botis
你能在这种情况下回复一个200状态和cors头吗?请查看https://dev59.com/drfna4cB1Zd3GeqPmhud和https://dev59.com/Gqrka4cB1Zd3GeqPaDjr#49959851。 - Jannes Botis
@JannesBotis 我不确定你的意思。当我有“x-api-key”头时,我会收到200 OK状态和cors头,但是当我删除“x-api-key”头时,我会收到403 Forbidden而没有cors头。 - PouncingPoodle
让我们在聊天中继续这个讨论 - PouncingPoodle
我正在使用AWS HTTP API Gateway,如何在AWS HTTP API Gateway中解决它? - Vinit Khandelwal
显示剩余3条评论
5个回答

11

在与@Jannes Botis进行了非常有帮助的讨论后,我找到了解决方案。

在template.yaml中,我将值更改为:

Globals:
  Function:
    Timeout: 10
  Api:
    Cors:
      AllowMethods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
      AllowHeaders: "'Content-Type,X-Amz-Date,X-Amz-Security-Token,Authorization,X-Api-Key,X-Requested-With,Accept,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Allow-Headers'"
      AllowOrigin: "'*'"

  MyAPIFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: myendpoint/
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      Events:
        GetMyData:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /myendpoint
            Method: get
        Options:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /myendpoint
            Method: options
            Auth:
              ApiKeyRequired: false

< p >注意:当你请求资源时会出现错误“No 'xxx' header is present on the requested resource.”,其中xxx可能是Access-Control-Allow-Methods、Access-Control-Allow-Origin和Access-Control-Allow-Headers,因此需要在AllowHeaders中添加它们。同时要注意,必须添加一个带有ApiKeyRequired: false的Options资源。

然后,你的选项和获取请求的响应应该具有相同的头信息:

headers: {
    "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,X-Amz-Security-Token,Authorization,X-Api-Key,X-Requested-With,Accept,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Allow-Headers",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT",
    "X-Requested-With": "*"
}

注意:'Accept' 必须存在,否则您将会收到“响应预检请求未通过访问控制检查:它没有HTTP ok状态。”的错误信息。

当您在postman中省略x-api-key时,您的预检请求必须能够通过200 OK。


CDK用户,您必须在corsPreflight参数中设置allowHeaders:['Content-Type', 'X-Amz-Date', 'X-Amz-Security-Token', 'Authorization', 'X-Api-Key', 'X-Requested-With', 'Accept', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Origin', 'Access-Control-Allow-Headers'] - Gregg Harrington
1
我正在使用AWS HTTP API Gateway,如何在AWS HTTP API Gateway中解决它? - Vinit Khandelwal

3
我将包含此响应以帮助那些仍然因此错误而苦恼的人。我花了一整天的时间来解决这个问题——阅读了关于CORS的所有内容,甚至将我的代码迁移到了新的AWS HttpAPI上(这可能是一件好事)。
重要的是,我一直困扰于错误信息:
“从源'http://localhost:8080'访问'https://api.example.com/user/list'时已被CORS策略阻止:对预检请求的响应未通过访问控制检查:所请求的资源上不存在'Access-Control-Allow-Origin'头。如果不透明的响应满足您的需求,请将请求的模式设置为'no-cors'以禁用CORS获取资源。”
这可能会让你走向错误的方向。事实上,我的问题与“Access-Control-Allow-Origin”头无关。实际上,我的问题的答案非常简单:我在“Authorization”标头中发送了一个JWT Token,并且我没有在响应中包含“Access-Control-Allow-Headers”条目。但愿错误消息更准确一些...
如果您正在阅读此文,您可能已经找到了许多有用的信息来源,但是这个网站对我非常有用:www.test-cors.org

这是在此处提到的“为Lambda或HTTP代理集成启用CORS支持”吗?https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html#apigateway-responding-to-cors-preflight - Anil
@redPanda 您提到不包括"Access-Controll-Allow-Origin"。代码中的哪个部分?Lambda函数还是请求?根据这些文档(https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html),如果您在httpAPI网关上启用了CORS,尤其是对于预检 (Preflight) OPTIONS 请求,"对于CORS请求,API Gateway会将配置的CORS头添加到与集成相关的响应中"。我在使用CURL发送POST请求时看到了这种行为('Access-Controll-Allow-Origin'被添加到标头),但在预检OPTIONS请求中没有看到。您有什么想法吗? - ehsk
如果你从自己的代码中发起请求,大多数客户端(例如postman/Paw)会为你包含这些内容,但是如果你需要在请求头中包含"Access-Control-Allow-Headers",请添加@ehsk。 - redPanda
如果你从自己的代码中发起请求,大多数客户端(例如postman/Paw)会自动包含这些信息,但如果没有的话,你需要在请求头中包含"Access-Control-Allow-Headers"。 - undefined

3
此错误也可能发生在您尝试访问错误的URL时。噢。在陷入CORS疯狂之前,请确认请求URL是否正确且资源可用。在我的情况下,我尝试访问错误的Lightsail URL后端。向这个不正确的URL发送POST请求会触发CORS错误。使用正确的URL一切正常。

1
我终于从 CodePen 中复制/粘贴了我的 URL,并发现有一个隐藏字符混入了我的 URL ‍♂️。 - Brendan Kendrick
2
好的评论,我的90%的CORS问题都是通过检查URL和资源可用性来解决的。 - Arthur Coimbra

1
如果有人在使用Node.js的Serverless时遇到了CORS策略的预检问题,这里提供一个简单的解决方案...
functions:
  externalHandler:
    handler: handler.handlerExport
    events:
      - http:
          path: handlerPath
          method: post
          cors:
            origin: '*' # <-- Specify allowed origin
            headers: # <-- Specify allowed headers
              - Content-Type
              - X-Amz-Date
              - Accept
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
            allowCredentials: false

在处理程序文件中,如果您正在使用Express。
...
const app = express();
app.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Credentials", true);
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
  res.header(
    "Access-Control-Allow-Headers",
    "x-www-form-urlencoded, Origin, X-Requested-With, Content-Type, Accept, Authorization"
  );
  next();
});
...

或者一般来说。
  const response = {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Credentials': true,
    },
    body: JSON.stringify({
      product: product
    }),
  };

获取更多信息,请参考无服务器文章


0
对于那些使用AWS CloudFront的用户,并且补充一下@PouncingPoodle的信息,你可以通过编辑你的CloudFront分发和编辑行为选项Origin request policyResponse headers policy来实现解决方案。 步骤1:打开你的CloudFlare分发,然后选择行为,选择适用的选项,然后点击编辑:

Edit Your CloudFront Behavior

第二步:向下滚动并更新“Origin request policy”。您有几个选项可供选择。在我的情况下,由于我从S3 Bucket访问EC2,所以选择很容易,但如果您的情况更复杂,您可能需要创建自己的策略。

Select the Origin Request Policy

第三步:更新您的“响应头策略”。此外,我们在那里有几个选项。在我的情况下,“CORS-with-preflight-and-SecurityHeadersPolicy”是我所需要的。

Select the Response Headers Policy

步骤4:保存并等待部署完成(需要2至5分钟)。

重要提示:如果您正在运行AWS CloudFront、EC2和Docker,问题仍然存在,请从头开始检查流程,因为有时候CORS错误可能会在浏览器中出现,但是您的Docker镜像会抛出不同的异常。

为了做到这一点,您可以在本地运行Docker镜像,执行HTML调用,并查看是否有问题。在我的情况下,不仅AWS设置错误,而且我的镜像抛出了一个报告缺少Python包的异常。

如果一切顺利,运行以下curl命令(Mac),并检查头部是否包含允许策略:

   curl -H "Origin:your_website_address.com" -v https://backend_address.com

这个命令还可以测试您的CloudFront。您希望得到的是以下信息:access-control-allow-origin, access-control-allow-methods和access-control-allow-credentials

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接