在Google App Engine上为Django应用程序启用CORS

时间:2017-08-29 08:37:57

标签: django google-app-engine nginx cors

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

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

2017年1月发行说明说

  

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

可以看到here

启用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"
    }
 ],
...

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

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需要这些字段 - email,password1,password2,其中password1应与password2相同。现在,当我发送正确的参数时,我得到HTTP 502说

  

否&#39;访问控制 - 允许 - 来源&#39;标头出现在请求的资源上。因此,不允许原始{origin-url}访问。响应具有HTTP状态代码502

但是当我发送password1与password2不同时,我得到HTTP 400响应,我确信它来自我的代码,因为如果password1和password2不匹配,则响应是代码中写的字典。同样在这种情况下,标题具有Access-Control-Allow-Origin *,但在前一种情况下,这不是真的

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

  

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

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

2 个答案:

答案 0 :(得分:4)

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

因为在HTTP 200响应的情况下,webapp应该进行数据库调用,webapp正在尝试连接到数据库服务器。这种连接耗时太长,一旦超出NGINX的超时时间,NGINX就会发送一个响应,网络浏览器的状态代码为502.

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

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

要点:

  1. 在GAE灵活环境中不需要openapi.yml文件为Django应用程序启用CORS
  2. 不要错过检查NGINX日志:p
  3. <强>更新

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

    像这样配置DATABASES:

    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”选项卡。您应该会看到一个包含实例连接名称列的表格。此列下的值是您的cloudsql-connection-string。

答案 1 :(得分: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;          
    }
}