我一直在尝试在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的正确方法吗?
答案 0 :(得分:4)
在敲了几天之后,我能够找出真正的问题。我的数据库服务器拒绝与webapp服务器的任何连接。
因为在HTTP 200响应的情况下,webapp应该进行数据库调用,webapp正在尝试连接到数据库服务器。这种连接耗时太长,一旦超出NGINX的超时时间,NGINX就会发送一个响应,网络浏览器的状态代码为502.
由于'access-control-allow-origin'标头是从webapp设置的,因此NGINX没有在其响应中设置该标头。因此,浏览器将其解释为CORS否认。
一旦我将我的webapp实例的数据库服务器的IP地址列入白名单,事情就开始顺利进行了
要点:
<强>更新强>
只是想更新我的答案,指定您不必将实例的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;
}
}