Ответ POST API заблокирован политикой CORS - React и Django Rest Framwork - PullRequest
0 голосов
/ 27 мая 2019

Я создал внутренний сервер в Django с Django Rest Framework и интерфейсом React.Мой фронт извлекает данные сзади через API.Каждое приложение находится в отдельном поддомене того же домена.Я использую Cloudflare для управления DNS и для SSL / безопасности.

У меня не было проблем с вызовами GET.Для вызовов POST я отправляю данные POST на сервер через форму, и я знаю, что это работает, поскольку есть изменения в базе данных (запись, созданная в этом случае).Тем не менее, я реализовал функцию «повторить до», используя axios и polly-js.Этот метод ждет, пока не получит ответ CREATED 201, в противном случае повторяется попытка.

Моя проблема заключается в том, что когда я отправляю форму в React, POST действительно принимается и обрабатывается моим внутренним сервером, но ответ блокируется.Таким образом, через 10-15 секунд я получаю сообщение об ошибке через консоль, и мой метод retry before отправляет другой запрос 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. 

То, что я уже сделал и не сработало:

  • IНе думайте, что это проблема с бэкэндом, поскольку POST проходит и запись создается.Но я внес в белый список все источники CORS в Django
  • Я добавил заголовок 'Access-Control-Allow-Origin': '*' в мой запрос POST через axios
  • Я вручную добавилтот же заголовок 'Access-Control-Allow-Origin': '*' из моего ответа Django DRF.

Оба запроса, которые я отправляю (первый - через отправку формы, второй - через автоматическую повторную попытку) идентичны (просматривается на вкладке Chrome network):

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

Ответ Iполучить, когда вторая попытка удалась:

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

Для справки, настройки CORS в Django

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 показывает мне ответ для 504 GATEWAY TIMEOUT первого запроса POST:

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?

Ожидаемый результат будет таким: когда я отправляю POST через форму, получаю обратно 201 (что будет принято и прочитано Chrome), чтобы я мог

  • Показать пользователяформа была правильно сохранена в базе данных
  • Не повторять POST, что приводит к двойной записи.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 27 мая 2019

Проверьте эту библиотеку.https://pypi.org/project/django-cors-headers. Это помогло мне решить ту же проблему с React.

0 голосов
/ 27 мая 2019

Вам не нужно помещать 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',
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...