【问题标题】:CORS errors when trying to fetch from new Google Cloud API Gateway尝试从新的 Google Cloud API Gateway 获取时出现 CORS 错误
【发布时间】:2021-01-24 14:40:11
【问题描述】:

我正在测试新的 API 网关以保护我的 React 应用程序的云功能。到目前为止,该过程比以前的替代方案要好得多,但是当我尝试从我的 React 应用程序访问我的 API 网关时,我目前遇到了 CORS 错误。我在我的 Cloud Function 中正确设置了 CORS 标头,但我不知道在 API Gateway 端点上执行相同操作的方法。我正在使用 Postman 测试对网关端点的请求,并且一切正常,所以它只是在我从我的 React 应用程序请求时。

错误:“从源 'https://example.netlify.app' 访问 'https://my-gateway-a12bcd345e67f89g0h.uc.gateway.dev/hello?key=example' 已被阻止CORS 策略:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors” ' 来获取禁用 CORS 的资源。"

希望对这个问题有所了解。谢谢!

【问题讨论】:

  • 解决方案:正确答案是@user14982714 回答的那个。我将在下面添加更多说明的答案。经过无数小时的调试,我发现 Google API Gateway 在后台使用了 Endpoints。这意味着如果您使用 allowCors 添加 x-google-endpoints 属性,则处理将传递到您的服务器,您可以在其中手动处理它。
  • 我刚刚添加了一个包含更多细节的解决方案。如果将来有人偶然发现这一点,请务必检查一下。在 openapi.yaml 中添加选项作为路径并调用返回正确标头的函数对于复杂的 API 来说不是可行的解决方案。 @ElektrikSpark 请检查一下,然后尝试一下。

标签: reactjs google-cloud-platform google-cloud-functions cors google-cloud-api-gateway


【解决方案1】:

我与其他 API 有类似的问题,所以我不确定在你的情况下同样的问题,但你可以尝试 - 在获取数据时在 react 应用程序中,假设你可以使用 axios 尝试

    axios.post('http://localhost:3003/signup',this.data,{headers:{'Access-Control- 
    Allow-Origin':'*','Content-Type': 'application/json'}})

在后端 - 试试这个 -

  let cors=require('./cors')
  app.options('*', cors());

它适用于我的情况,希望对您有所帮助。

【讨论】:

  • 感谢伊戈尔的回复。不幸的是,它仍然说“请求的资源上没有'Access-Control-Allow-Origin'标头。”,所以我相信这严格来说是一个服务器端问题。
  • 您的想法是正确的,但是,OP 所说的 GCP API 网关层阻止您将请求路由到实际代码。解决方案在于在 openapi.yaml 规范中正确指定 path.options 路由并将其路由到 CORS 特定的后端。
【解决方案2】:

原来 API Gateway 目前不支持 CORS。

Reference.

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,并使用负载均衡器解决了它(最初用于将自定义域添加到我的 API 网关)。 我使用负载均衡器将缺少的标头添加到响应中。

    您只需要添加“Access-Control-Origin”标头:

    全部允许

    访问控制来源:'*'

    允许特定来源 访问控制允许来源:http://example.com:8080

    您可以在这里找到说明GCP - Creating custom headers

    如果您没有实施负载平衡器, 你可以按照这个教程来实现一个新的Google API Gateway, Load Balancer and Content Delivery Network

    您可以在https://www.w3.org/wiki/CORS_Enabled 找到有关 CORS 的更多信息。

    【讨论】:

      【解决方案4】:

      目前尚不支持此功能,但是,有一个临时的解决方法可以使其正常工作。您应该将options 添加到openapi.yaml 中的路径中。此外,getoptions 操作都应该指向同一个云函数,因为 options 请求随后充当云函数的预热请求。就延迟而言,这是最有效的设置。这是一个简化的例子:

      paths:
        /helloworld:
          get:
            operationId: getHelloWorld
            x-google-backend:
              address: $CLOUD_FUNCTION_ADDRESS
            responses:
              '200':
                description: A successful response
          options:
            operationId: corsHelloWorld
            x-google-backend:
              address: $CLOUD_FUNCTION_ADDRESS
            responses:
              '200':
                description: A successful response
      

      然后,在您的云功能后端,您还必须处理预检请求 (source)。 Google 文档还提供了一个示例with authentication,其中包含一些额外的标头。下面是一个没有认证的例子:

      def cors_enabled_function(request):
          # For more information about CORS and CORS preflight requests, see
          # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
          # for more information.
      
          # Set CORS headers for the preflight request
          if request.method == 'OPTIONS':
              # Allows GET requests from any origin with the Content-Type
              # header and caches preflight response for an 3600s
              headers = {
                  'Access-Control-Allow-Origin': '*',
                  'Access-Control-Allow-Methods': 'GET',
                  'Access-Control-Allow-Headers': 'Content-Type',
                  'Access-Control-Max-Age': '3600'
              }
      
              return ('', 204, headers)
      
          # Set CORS headers for the main request
          headers = {
              'Access-Control-Allow-Origin': '*'
          }
      
          return ('Hello World!', 200, headers)
      

      注意:API 网关未以适当方式管理预检请求的缺点会导致两次运行云功能的惩罚。但是你的第二个请求应该总是非常快,因为第一个请求是一个预热请求。

      【讨论】:

      • 嗨,你能在这里分享完整的开放 api 规范吗,我在我的开放 api 规范中添加了选项,但是在 GCP 控制台上传时它说无效的定义“选项”选项: operationId:corsRequest x-google-backend :地址:>-us-east1-neodev-305805.cloudfunctions.net/my-function 响应:'200':产生:-应用程序/json 方案:-https swagger:'2.0'
      • 我扩展了 openapi 规范并给出了更多说明!祝你好运:)
      • @SundarJavaDeveloper 这解决了吗?我尝试了同样的方法,现在请求甚至没有向服务器后端发送选项。如何在yaml中配置options,让GCP API Gateway先发送OPTIONS?
      • CORS 预检请求是一个 CORS 请求,用于检查 CORS 协议是否被理解以及服务器是否知道使用特定的方法和标头。这是一个 OPTIONS 请求,使用三个 HTTP 请求标头: Access-Control-Request-Method 、 Access-Control-Request-Headers 和 Origin 标头。在我发布的 yaml sn-p 中有一个示例选项操作。
      • 你节省了我的时间。 YAML 文件中的选项解决了我的 API Gateway 自定义域端点问题的 cors 问题
      【解决方案5】:
      swagger: "2.0"
      host: "my-cool-api.endpoints.my-project-id.cloud.goog"
      x-google-endpoints:
      - name: "my-cool-api.endpoints.my-project-id.cloud.goog"
        allowCors: True
      

      注意:主机和名称应具有相同的 API 端点名称

      在配置文件中配置这些行会启用 API GATEWAY 的 CORS

      [参考][1]

      [1]:https://cloud.google.com/endpoints/docs/openapi/support-cors#:~:text=CORS%20(Cross%2Dorigin%20resource%20sharing,would%20prevent%20cross% 2Dorigin%20 个请求。

      【讨论】:

      • 这是否已经适用于 api 网关?您的示例基于云端点,不存在此问题。
      【解决方案6】:

      解决方案

      这里是解决方案。正如 user14982714 所说。将主机和 x-google-endpoints 添加到您的顶级 oepnapi.yaml 文件中:

      host: my-cool-api.endpoints.my-project-id.cloud.goog
      x-google-endpoints:
      - name: my-cool-api.endpoints.my-project-id.cloud.goog
        allowCors: True
      

      但是,请务必将 my-cool-api.endpoints.my-project-id.cloud.goog 替换为您的 API 托管服务 URL。这可以在您的谷歌云控制台中的 API Gateway API 下找到:

      出于隐私考虑,我覆盖了端点名称的开头,但是,您的名称也应该以 .cloud.goog 结尾。如果您还没有部署配置,请在没有 x-google-endpoints 和主机的情况下部署它,然后更新它以包含两者。 (要更新您的配置,请转到 API Gateway -> Your API -> Gateways Tab -> Your Gateway -> Edit-> Change API Config -> Create New)

      说明

      现在解释为什么这适用于 Google Cloud API Gateway。 API 网关在后台使用端点。大多数人不知道是这种情况,但是,在放弃 API 网关并回到端点后,我注意到我的 API 网关列在端点服务下。它们不会显示在 UI 中,但使用 gcloud CLI,运行此命令 gcloud endpoints services list,您应该会看到您的 API 网关。疯狂的!但谷歌经常这样做。

      知道这一点后,我尝试将allowCors: true 添加到x-google-endpoints 和中提琴。有效。我希望这对那里的人有所帮助。

      【讨论】:

      • 您需要支持 CORS 的云端点。但是,最初的问题是关于使用云功能作为后端。
      • 这确实有效。如果像我一样,您的 API 网关位于负载均衡器后面以支持自定义域名,您应该使用命令 gcloud endpoints services list 中显示的原始 cloud.goog 服务名称——而不是自定义域名。
      • 感谢您的详细说明,如果我误解了,请见谅。我认为在您的特定情况下,这是使用负载均衡器。您能否添加一个关于您的 openapi 规范的详细示例?
      猜你喜欢
      • 2018-06-23
      • 2022-11-07
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 2020-06-08
      • 2020-01-14
      • 2016-06-06
      • 2021-10-30
      相关资源
      最近更新 更多