POST API响应被CORS策略阻止-React和Django Rest Framwork

时间:2019-05-27 12:31:50

标签: django reactjs google-chrome django-rest-framework cors

我已经使用Django Rest Framework和Django在Django中创建了一个后端服务器。我的前台通过API从后台检索数据。每个应用程序都位于同一域的不同子域中。我用 Cloudflare用于管理DNS和SSL /安全性。

我对GET通话没有任何问题。对于POST调用,我通过表单将POST数据发送到服务器,并且我知道它可以工作,因为数据库有更改(在此实例中创建的记录)。但是,我已经使用axios和polly-js实现了“重试直到”功能。该方法一直等待,直到收到201 CREATED响应,否则重试。

我的问题是,当我在React上提交表单时,确实由后端服务器接收并处理了POST,但是响应被阻止了。因此,在10到15秒钟后,我通过控制台收到一条错误消息,而我的“重试直到”方法发送了另一个POST请求。 Chrome并未阻止第二个响应,并且我收到201状态。但是总体效果是我现在在数据库中有2条相同的记录,因为第一个调用没有“接收”响应并重试。

我得到的控制台错误是:

Access to XMLHttpRequest at 'https://subdomain.domain.io/' from origin 'https://api.domain.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 

我已经做过但没有成功的事情:

  • 我不认为这是一个后端问题,因为POST经过并创建了记录。但是我已经将所有CORS起源列入了Django
  • 我已通过axios将标头'Access-Control-Allow-Origin':'*'添加到我的POST请求中
  • 我从Django DRF响应中手动添加了相同的'Access-Control-Allow-Origin':'*'标头。

我发送的两个请求(第一个通过表单提交发送,第二个通过自动重试发送)都相同(通过Chrome网络标签可见):

Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Origin: https://subdomain.domain.io
Referer: https://subdomain.domain.io/path
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36

我的POST和重试方法:

const postData = (url, data, headers) => {

    headers['Access-Control-Allow-Origin'] = "*"

    return polly()
      .waitAndRetry([100, 200, 400, 1000])
      .executeForPromise(async () => {
        const rsp = await axios.post(url, data, headers);

        if (rsp.status < 210) {

          return rsp.data;

        }

        return Promise.reject(rsp);
      });
  };

第二次尝试成功时得到的响应:

access-control-allow-origin: *
allow: GET, POST, HEAD, OPTIONS
cf-ray: 4dd7cbccce256948-CDG
content-length: 364
content-type: application/json
date: Mon, 27 May 2019 11:54:47 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
status: 201
strict-transport-security: max-age=2592000; includeSubDomains; preload
vary: Accept, Origin
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN

作为参考,Django中的CORS设置

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django_otp.middleware.OTPMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]


CORS_ORIGIN_ALLOW_ALL = True


CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'access-control-allow-origin'
)

编辑

Firefox向我显示了对第一个POST请求的504 GATEWAY TIMEOUT的响应:

cf-ray: 4dd82ac15f42cd97-CDG
content-type: text/html; charset=UTF-8
date: Mon, 27 May 2019 13:00:36 GMT
expect-ct: max-age=604800, report-uri="ht….com/cdn-cgi/beacon/expect-ct"
expires: Thu, 01 Jan 1970 00:00:01 GMT
pragma: no-cache
server: cloudflare
set-cookie: __cfduid=d0a3a9ee872171ada14cb…n=.wisly.io; HttpOnly; Secure
set-cookie: cf_use_ob=0; path=/; expires=Mon, 27-May-19 13:01:06 GMT
strict-transport-security: max-age=2592000; includeSubDomains; preload
x-content-type-options: nosniff
X-Firefox-Spdy: h2

缺少Access-Control-Allow-Origin,但这是我的后端代码的一部分。 Cloudflare会发生什么事吗?

预期结果是,当我通过表单过帐时,收到201的回信(Chrome会接受并读取它),以便我可以

  • 向用户显示表单已正确保存到数据库中
  • 不重试POST,导致双重输入。

谢谢!

2 个答案:

答案 0 :(得分:0)

您无需将access-control-allow-origin放在CORS_ALLOW_HEADERS中。
Django CORS将根据您的配置自动添加请求。

您可以尝试一些技巧:

  • 使用default_headers而不是放置所有默认标题(只是为了改进代码)
  • 我已经遇到了Chrome发送的一些基本标头的问题,而我的应用不允许这些标头,因此我不得不添加
from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
    'Cache-Control', 'If-Modified-Since',
)
  • 尝试添加“可信来源”
CSRF_TRUSTED_ORIGINS = (
    '*.yourdomain.com',
)

答案 1 :(得分:0)

签出此库。 https://pypi.org/project/django-cors-headers。它帮助我用React解决了同样的问题。