简体   繁体   English

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

[英]Enabling CORS on Google App Engine for a Django Application

I have been trying to enable CORS headers on Google app engine but none of the methods that I found over the internet worked for me.我一直在尝试在 Google 应用引擎上启用 CORS 标头,但我在互联网上找到的任何方法都不适合我。

My application is on Python/Django and I want my frontend application (which is hosted separately) to be able to make API calls to my backend platform on Google App Engine.我的应用程序在 Python/Django 上,我希望我的前端应用程序(单独托管)能够在 Google App Engine 上对我的后端平台进行 API 调用。

The January 2017 release notes say that 2017 年 1 月的发行说明说

We are changing the behavior of the Extensible Service Proxy (ESP) to deny cross-origin resource sharing (CORS) requests by default我们正在更改可扩展服务代理 (ESP) 的行为,以默认拒绝跨源资源共享 (CORS) 请求

It can be seen here可以在这里看到

And the solution to enable CORS given by them is to add the following snippet to the service's OpenAPI configuration.他们提供的启用 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"
    }
 ],
...

So I followed this example and created two files in my code base所以我按照这个例子在我的代码库中创建了两个文件

openapi.yml : 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: 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"

Then I ran this command:然后我运行了这个命令:

gcloud service-management deploy openapi.yml

Then I edited my app.yml file to make it look like this (The addition was endpoints_api_service. Before adding this, the app was getting deployed without any errors):然后我编辑了我的 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>"

Then I just deployed the application with然后我刚刚部署了应用程序

gcloud app deploy

Now, the app got deployed successfully but it is behaving strangely.现在,该应用程序已成功部署,但行为异常。 All the requests which are supposed to return a 200 response still throw CORS error but the ones which return a 400 status do work.所有应该返回 200 响应的请求仍然会抛出 CORS 错误,但返回 400 状态的请求确实有效。

For example - The sign up API expects these fields - email, password1, password2 where password1 should be same as password2.例如 - 注册 API 需要这些字段 - 电子邮件、密码 1、密码 2,其中密码 1 应与密码 2 相同。 Now when I send correct parameters, I get HTTP 502 saying现在当我发送正确的参数时,我得到 HTTP 502 说

No 'Access-Control-Allow-Origin' header is present on the requested resource.请求的资源上不存在“Access-Control-Allow-Origin”标头。 Origin {origin-url} is therefore not allowed access.因此不允许访问源 {origin-url}。 The response had HTTP status code 502响应的 HTTP 状态代码为 502

But when I send password1 not same as password2, I get HTTP 400 response which I am sure is coming from my code because the response is a dictionary written in the code if password1 and password2 do not match.但是,当我发送的 password1 与 password2 不同时,我得到 HTTP 400 响应,我确信它来自我的代码,因为如果 password1 和 password2 不匹配,响应是用代码编写的字典。 Also in this case, the headers have Access-Control-Allow-Origin as * but in the former case, that was not true同样在这种情况下,标头的 Access-Control-Allow-Origin 为 * 但在前一种情况下,情况并非如此

I also checked my nginx error logs and it says我还检查了我的 nginx 错误日志,它说

*27462 upstream prematurely closed connection while reading response header *27462 上游在读取响应头时过早关闭连接

What am I doing wrong here?我在这里做错了什么? Is this the right way to enable CORS in GAE?这是在 GAE 中启用 CORS 的正确方法吗?

After banging my head for several days, I was able to figure out the the real problem.折腾了几天后,我终于找到了真正的问题所在。 My database server was denying any connection to the webapp server.我的数据库服务器拒绝与 webapp 服务器的任何连接。

Since in case of a HTTP 200 response, the webapp is supposed to make a database call, the webapp was trying to connect to the database server.由于在 HTTP 200 响应的情况下,webapp 应该进行数据库调用,因此 webapp 试图连接到数据库服务器。 This connection was taking too long and as soon as it reached beyond the NGINX's timeout time, NGINX used to send a response to the web browser with the status code as 502.此连接花费的时间太长,一旦超过 NGINX 的超时时间,NGINX 就会向 Web 浏览器发送状态代码为 502 的响应。

Since the 'access-control-allow-origin' header was being set from the webapp, NGINX did not set that header in its response.由于 'access-control-allow-origin' 标头是从 webapp 设置的,NGINX 没有在其响应中设置该标头。 Hence the browser was interpreting it as a CORS denial.因此浏览器将其解释为 CORS 拒绝。

As soon as I whitelisted my webapp's instance's IP address for the database server, things started running smoothly一旦我将我的 webapp 实例的 IP 地址列入数据库服务器的白名单,事情就开始顺利运行

Summary:总结:

  1. There is no need of openapi.yml file to enable CORS for a Django application on GAE flexible environment不需要 openapi.yml 文件来为 GAE 灵活环境中的 Django 应用程序启用 CORS
  2. Do not miss to check the NGINX logs :p不要错过检查 NGINX 日志:p

Update:更新:

Just wanted to update my answer to specify the way through which you won't have to add you instance's IP to the whitelisted IP(s) of the SQL instance只是想更新我的答案以指定您不必将实例的 IP 添加到 SQL 实例的白名单 IP 的方式

Configure the DATABASES like this:像这样配置数据库:

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

Note the HOST key in the databases.请注意数据库中的 HOST 键。 GAE has a way through which you won't have to whitelist your instance's IP but for that to work, the host should be the cloudsql-connection-string and NOT the IP of the SQL instance. GAE 有一种方法,您不必将实例的 IP 列入白名单,但要使其正常工作,主机应该是cloudsql-connection-string而不是 SQL 实例的 IP。

If you are not sure what's your cloudsql-connection-string, go to the Google cloud platform dashboard and select the SQL tab under the Storage section.如果您不确定您的 cloudsql-connection-string 是什么,请转到 Google 云平台仪表板并选择存储部分下的 SQL 选项卡。 You should see a table with a column Instance connection name .您应该会看到一个包含Instance connection name列的表。 The value under this column is your cloudsql-connection-string.此列下的值是您的 cloudsql-connection-string。

Nginx as your reverse proxy, so, as the gateway to your server, should be who manage CORS against client browser requests, as first contact from beyond to your system. Nginx 作为您的反向代理,因此,作为您服务器的网关,应该由谁来管理针对客户端浏览器请求的 CORS,作为您系统之外的第一个联系。 Should not be any of the backend servers (neither your database, neither anything).不应是任何后端服务器(既不是您的数据库,也不是任何东西)。

Here you got my default config to enable CORS in nginx from Ajax calls to a REST service of my own (backserver glassfish).在这里,您获得了我的默认配置,用于从 Ajax 调用到我自己的 REST 服务(后台服务器 glassfish)在 nginx 中启用 CORS。 Feel free to check and use it and hope it serves to you.随意检查和使用它,希望它对你有用。

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;          
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM