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

Paw*_*Kam 5 nginx amazon-ec2 cors django-cors-headers

我使用 django-cors-headers 3.1.1 来处理 Django 后端和 Javascript 前端应用程序之间的请求和响应。传输是不安全的(即http,而不是https)。

\n\n

当本地托管时,一切正常。但在服务器上部署后,我不再看到 CORS 标头。

\n\n

以下是正在开发中的标头:\n在此输入图像描述\n生产中:\n在此输入图像描述

\n\n

错误信息:

\n\n
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.\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的 nginx 配置如下:

\n\n
server {\n    listen 80;\n    server_name [HOST_IP];\n\n    location / {\n        include proxy_params;\n        proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;\n\n        add_header \'Access-Control-Allow-Origin\' \'*\';\n        add_header \'Access-Control-Allow-Methods\' \'GET, PUT, OPTIONS\';\n        add_header \'Access-Control-Allow-Headers\' \'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range\';\n        add_header \'Access-Control-Max-Age\' 86400;\n\n        if ($request_method = \'OPTIONS\') {\n            add_header \'Content-Type\' \'text/html; charset=utf-8\';\n            add_header \'Content-Length\' 0;\n            return 204;\n        }\n        if ($request_method = \'PUT\') {\n            add_header \'Access-Control-Expose-Headers\' \'Content-Length,Content-Range\';\n        }\n        if ($request_method = \'GET\') {\n            add_header \'Access-Control-Expose-Headers\' \'Content-Length,Content-Range\';\n        }\n    }\n\n    location /static/ {\n        autoindex on;\n        alias /home/ubuntu/[path_to_app]/site/static/;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

django-cors-headers\xe2\x80\x99 设置现在在开发和生产中是相同的:

\n\n
INSTALLED_APPS = (\n    \xe2\x80\xa6\n    "corsheaders",\n    \xe2\x80\xa6\n)\nMIDDLEWARE = [\n    \xe2\x80\xa6\n    "corsheaders.middleware.CorsMiddleware",\n    "django.middleware.common.CommonMiddleware",\n    \xe2\x80\xa6\n]\nCORS_ORIGIN_ALLOW_ALL = True\nCORS_ALLOW_METHODS = [\'DELETE\',\'GET\',\'OPTIONS\',\'PATCH\',\'POST\',\'PUT\']\n
Run Code Online (Sandbox Code Playgroud)\n\n

在客户端,我尝试添加 \xe2\x80\x98\'Access-Control-Request-Method\xe2\x80\x99: \xe2\x80\x98PUT\xe2\x80\x99 标头,但这被拒绝浏览器。\xe2\x80\x99s 在客户端调用中注意到异常:

\n\n
  axios({\n    method: \'put\',\n    url: `${this.backendUrl}/api/assets/`,\n    data: formData,\n    headers: {\n      \'Content-Type\': \'application/octet-stream\',\n    }\n  })\n
Run Code Online (Sandbox Code Playgroud)\n\n

另外,我\xe2\x80\x99m第一次尝试在Amazon AWS EC2上托管,所以也许有一些我不知道的必需的AWS配置。例如,是否需要使用API​​网关启用CORS?文档并没有这么说(\xe2\x80\x98如果您使用的是 API Gateway Import API,则可以使用 OpenAPI 文件\xe2\x80\x99 设置 CORS 支持)。

\n\n

前端应用程序托管在具有以下 CORS 策略的 S3 存储桶上:

\n\n
<?xml version="1.0" encoding="UTF-8"?>\n<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">\n<CORSRule>\n    <AllowedOrigin>*</AllowedOrigin>\n    <AllowedMethod>PUT</AllowedMethod>\n    <AllowedMethod>POST</AllowedMethod>\n    <AllowedMethod>GET</AllowedMethod>\n    <MaxAgeSeconds>3000</MaxAgeSeconds>\n    <AllowedHeader>*</AllowedHeader>\n</CORSRule>\n</CORSConfiguration>\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

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

\n\n

我也尝试像这个问题一样设置代理标头,但是如果不太了解 nginx,这注定会失败。

\n

Paw*_*Kam 1

我通过改变三件事成功解决了这个问题:

\n\n

AWS

\n\n

我注意到AWS 文档指出:

\n\n
\n

已为 Amazon EC2 API 启用 CORS,并可供您使用。\n 您无需执行任何额外的配置步骤\n即可开始使用此功能。您调用 Amazon EC2 API 的方式没有变化;它们仍必须使用有效的 AWS 凭证进行签名,以确保 AWS 可以对请求者进行身份验证。[\xe2\x80\xa6]

\n
\n\n

这通常由 AWS SDK 或 CLI 处理,但在我的例子中,我没有使用它们,所以我必须添加AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY。就我而言,我只是使用aws4 库

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

不过,我\xe2\x80\x99已经看到了大量如何添加AWS Signature v.4而无需任何额外依赖的示例。

\n\n

NGINX

\n\n

在 nginx 配置中,我将所有 add_headers 语句放入条件代码块中。想法来自这篇文章

\n\n
server {\n    listen 80;\n    server_name [HOST_IP];\n\n    location / {\n        include proxy_params;\n        proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;\n\n\n        if ($request_method = \'OPTIONS\') {\n            add_header \'Access-Control-Allow-Origin\' \'*\';\n            add_header \'Access-Control-Allow-Methods\' \'GET, PUT, OPTIONS, POST, DELETE\';\n            add_header \'Access-Control-Allow-Headers\' \'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date\';\n            add_header \'Access-Control-Max-Age\' 86400;\n            add_header \'Content-Type\' \'text/html; charset=utf-8\';\n            add_header \'Content-Length\' 0;\n            return 204;\n        }\n        if ($request_method = \'PUT\') {\n            add_header \'Access-Control-Allow-Methods\' \'GET, PUT, OPTIONS, POST, DELETE\';\n            add_header \'Access-Control-Allow-Headers\' \'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date\';\n            add_header \'Access-Control-Expose-Headers\' \'Content-Length,Content-Range\';\n        }\n        if ($request_method = \'GET\') {\n            add_header \'Access-Control-Allow-Origin\' \'*\';\n            add_header \'Access-Control-Allow-Methods\' \'GET, PUT, OPTIONS, POST, DELETE\';\n            add_header \'Access-Control-Allow-Headers\' \'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date\';\n            add_header \'Access-Control-Expose-Headers\' \'Content-Length,Content-Range\';\n        }\n    }\n\n    location /static/ {\n        autoindex on;\n        alias /home/ubuntu/analizy/be/site/static/;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

Django-cors-header

\n\n

在这里添加非默认标头就足够了。

\n\n
from corsheaders.defaults import default_headers\nCORS_ALLOW_HEADERS = list(default_headers) + [\n    \'X-Amz-Date\',\n]\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

希望这会对某人有所帮助。

\n