django-cors-headers和nginx配置:预检请求响应缺少CORS头部

5
我使用django-cors-headers 3.1.1来处理Django后端和Javascript前端应用程序之间的请求和响应。传输是非安全的(即http,而不是https)。
当本地托管时,一切正常。但是在服务器上部署后,我停止看到CORS标头。
以下是开发中的标头: enter image description here 以及生产中的标头: enter image description here 错误消息:
Access to XMLHttpRequest at 'http://[HOST_IP]/api/assets/' from origin 'http://my_custom_domain.eu' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我的nginx配置如下:

server {
    listen 80;
    server_name [HOST_IP];

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Max-Age' 86400;

        if ($request_method = 'OPTIONS') {
            add_header 'Content-Type' 'text/html; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        if ($request_method = 'PUT') {
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
    }

    location /static/ {
        autoindex on;
        alias /home/ubuntu/[path_to_app]/site/static/;
    }
}

django-cors-headers的设置现在在开发和生产中是相同的:
INSTALLED_APPS = (
    …
    "corsheaders",
    …
)
MIDDLEWARE = [
    …
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    …
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ['DELETE','GET','OPTIONS','PATCH','POST','PUT']

在客户端,我尝试添加"Access-Control-Request-Method": "PUT"头部,但浏览器拒绝了此操作。客户端调用中没有任何异常。
  axios({
    method: 'put',
    url: `${this.backendUrl}/api/assets/`,
    data: formData,
    headers: {
      'Content-Type': 'application/octet-stream',
    }
  })

此外,我第一次尝试在Amazon AWS EC2上进行主机托管,所以可能有一些我不知道的必需的AWS配置。例如,是否需要使用API网关启用CORS? 文档没有这样说明(“如果您正在使用API Gateway导入API,则可以使用OpenAPI文件设置CORS支持”)。
前端应用程序托管在具有以下CORS策略的S3存储桶中:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

我在这里缺少什么?是否需要一些必要的服务器端(尤其是nginx)配置?

我尝试了其他一些解决方案:

我怀疑请求/响应来源是否正确(例如APPEND_SLASH变量)。但如果是这种情况,本地托管时不应该引发错误吗?

我还尝试设置代理头,就像this question中所述,但由于不太了解nginx,这注定会失败。

1个回答

1

我通过更改3个事项解决了这个问题:

AWS

我注意到AWS文档中提到:

CORS已经为Amazon EC2 API启用,并且可以使用。您无需执行任何其他配置步骤即可开始使用此功能。对于调用Amazon EC2 API的方式没有任何更改;它们仍必须使用有效的AWS凭据进行签名,以确保AWS可以验证请求者。[...]

通常由AWS SDK或CLI处理此问题,但在我的情况下,我没有使用它们之一,因此我不得不添加AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY。在我的情况下,我只是使用了aws4库:

  axios(aws4.sign({
    accessKeyId: this.awsAccessKey,
    secretAccessKey: this.awsSecretAccessKey,
    method: 'put',
    url: `${this.backendUrl}/api/assets/`,
    data: formData,
    body: JSON.stringify(formData),
    service: 'ec2',
    region: 'eu-central-1',
    path: '/',
    headers: {
      'Content-Type': 'application/octet-stream'
    }
  }))

我看过很多例子,如何添加AWS Signature v.4而不需要任何额外的依赖。

NGINX

在nginx配置中,我将所有add_headers语句放置在条件代码块中。这个想法来自于this post

server {
    listen 80;
    server_name [HOST_IP];

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;


        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
            add_header 'Access-Control-Max-Age' 86400;
            add_header 'Content-Type' 'text/html; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        if ($request_method = 'PUT') {
            add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
    }

    location /static/ {
        autoindex on;
        alias /home/ubuntu/analizy/be/site/static/;
    }
}

Django-cors-header

这里只需要添加非默认标头即可。

from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
    'X-Amz-Date',
]

希望这能帮助到某些人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接