8

我一直在尝试在 Google 应用程序引擎上启用 CORS 标头,但我在互联网上找到的所有方法都不适合我。

我的应用程序在 Python/Django 上,我希望我的前端应用程序(单独托管)能够在 Google App Engine 上对我的后端平台进行 API 调用。

2017 年 1 月的发行说明说

我们正在更改可扩展服务代理 (ESP) 的行为,以默认拒绝跨域资源共享 (CORS) 请求

可以在这里看到

他们提供的启用 CORS 的解决方案是将以下代码段添加到服务的 OpenAPI 配置中。

"host": "echo-api.endpoints.YOUR_PROJECT_ID.cloud.goog",
"x-google-endpoints": [
    {
      "name": "echo-api.endpoints.YOUR_PROJECT_ID.cloud.goog",
      "allowCors": "true"
    }
 ],
...

所以我按照这个例子在我的代码库中创建了两个文件

openapi.yml:

swagger: "2.0"
info:
  description: "Google Cloud Endpoints APIs"
  title: "APIs"
  version: "1.0.0"
host: "echo-api.endpoints.<PROJECT-ID>.cloud.goog"  
x-google-endpoints:
 - name: "echo-api.endpoints.<PROJECT-ID>.cloud.goog"
   allowCors: "true"
paths:
  "/api/v1/sign-up":
    post:
      description: "Sends an email for verfication"
      operationId: "signup"
      produces:
      - "application/json"
      responses:
        200:
          description: "OK"
      parameters:
      - description: "Email address of the user"
        in: body
        name: email
        required: true
        schema:
          type: string
      - description: "password1"
        in: body
        name: password1
        required: true
        schema:
          type: string
      - description: "password2"
        in: body
        name: password2
        required: true
        schema:
          type: string

openapi-appengine.yml:

swagger: "2.0"
info:
  description: "Google Cloud Endpoints API fo localinsights backend server"
  title: "Localinsights APIs"
  version: "1.0.0"
host: "<PROJECT-ID>.appspot.com"

然后我运行了这个命令:

gcloud service-management deploy openapi.yml

然后我编辑了我的 app.yml 文件,使其看起来像这样(添加的是 endpoints_api_service。在添加之前,应用程序正在部署,没有任何错误):

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT myapp.wsgi

beta_settings:
    cloud_sql_instances: <cloud instance>

runtime_config: 
  python_version: 3

automatic_scaling:
  min_num_instances: 1
  max_num_instances: 1

resources:
  cpu: 1
  memory_gb: 0.90
  disk_size_gb: 10  

env_variables:
  DJANGO_SETTINGS_MODULE: myapp.settings.staging
  DATABASE_URL: <dj-database-url>

endpoints_api_service:
  name: "<PROJECT-ID>.appspot.com"
  config_id: "<CONFIG-ID>"

然后我刚刚部署了应用程序

gcloud app deploy

现在,该应用程序已成功部署,但行为异常。所有应该返回 200 响应的请求仍然会引发 CORS 错误,但返回 400 状态的请求确实有效。

例如 - 注册 API 需要这些字段 - 电子邮件、密码 1、密码 2,其中密码 1 应与密码 2 相同。现在当我发送正确的参数时,我得到 HTTP 502 说

请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin {origin-url} 不允许访问。响应具有 HTTP 状态代码 502

但是,当我发送与密码 2 不同的密码 1 时,我会收到 HTTP 400 响应,我确信该响应来自我的代码,因为如果密码 1 和密码 2 不匹配,则响应是用代码编写的字典。同样在这种情况下,标头的 Access-Control-Allow-Origin 为 * 但在前一种情况下,这是不正确的

我还检查了我的 nginx 错误日志,它说

*27462 在读取响应标头时上游过早关闭连接

我在这里做错了什么?这是在 GAE 中启用 CORS 的正确方法吗?

4

2 回答 2

4

在敲了几天的头之后,我能够找出真正的问题。我的数据库服务器拒绝与 webapp 服务器的任何连接。

由于在 HTTP 200 响应的情况下,webapp 应该进行数据库调用,所以 webapp 试图连接到数据库服务器。此连接花费的时间太长,一旦超过 NGINX 的超时时间,NGINX 就会向 Web 浏览器发送响应,状态码为 502。

由于 'access-control-allow-origin' 标头是从 web 应用程序设置的,NGINX 没有在其响应中设置该标头。因此,浏览器将其解释为 CORS 拒绝。

一旦我将我的 webapp 实例的数据库服务器 IP 地址列入白名单,事情就开始顺利运行

概括:

  1. 无需 openapi.yml 文件即可在 GAE 柔性环境中为 Django 应用程序启用 CORS
  2. 不要错过检查 NGINX 日志:p

更新:

只是想更新我的答案以指定您不必将实例的 IP 添加到 SQL 实例的白名单 IP 的方式

像这样配置数据库:

DATABASES = {
    'HOST': <your-cloudsql-connection-string>, # This is the tricky part
    'ENGINE': <db-backend>,
    'NAME': <db-name>,
    'USER': <user>,
    'PASSWORD': <password>
}

请注意数据库中的 HOST 键。GAE 有一种方法,您不必将实例的 IP 列入白名单,但要使其正常工作,主机应该是cloudsql-connection-string而不是 SQL 实例的 IP。

如果您不确定您的 cloudsql-connection-string 是什么,请转到 Google 云平台仪表板并选择存储部分下的 SQL 选项卡。您应该会看到一个包含Instance connection name列的表。此列下的值是您的 cloudsql-connection-string。

于 2017-09-05T02:19:46.907 回答
1

Nginx 作为您的反向代理,因此,作为您服务器的网关,应该由谁管理 CORS 针对客户端浏览器请求,作为您系统之外的第一个联系人。不应该是任何后端服务器(既不是您的数据库,也不是任何东西)。

在这里,您获得了我的默认配置,以在 nginx 中启用 CORS,从 Ajax 调用到我自己的 REST 服务(backserver glassfish)。随意检查和使用它,希望它对你有用。

server {
    listen   80; ## listen for ipv4; this line is default and implied
    server_name codevault;

    #Glassfish
    location /GameFactoryService/   {

            index index.html;

                add_header Access-Control-Allow-Origin $http_origin;

                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-NginX-Proxy true;
                proxy_ssl_session_reuse off;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_set_header X-Forwarded-Server $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://127.0.0.1:18000/GameFactoryService/;

        }

        #static content
    location / {
        root /usr/share/nginx_static_content;
    }

    error_page 500 501 502 503 504 505 506 507 508 509 510 511 /50x.html;

    #error
        location = /50x.html {

      add_header Access-Control-Allow-Origin $http_origin;          
          internal;          
    }
}
于 2017-09-07T22:57:29.473 回答