Введение

CORS - это сокращение от Cross-Origin-Resource-Sharing. Это механизм, который защищает пользователей от таких атак, как межсайтовый скриптинг (XSS). Когда вы запрашиваете ресурсы сервера из другого домена, вы должны быть в белом списке сервера. Если вы разрабатываете интерфейс с помощью Chrome и хотите fetch данные с сервера с другим доменом, вы можете получить ошибку CORS. Например, в одном из моих проектов React использовался как интерфейс, а Flask - как бэкэнд. Когда я хотел получить данные с сервера Flask, я получил эту ошибку:

Что происходит за кулисами?

Вы видите приведенное выше сообщение об ошибке, потому что всякий раз, когда вы хотите отправить HTTP-запрос через браузер, например Chrome, он сначала отправит на сервер предварительный запрос, а затем ваш. Например, если вы хотите отправить запрос POST на свой сервер, вы должны увидеть две записи запросов в журналах вашего сервера с разными методами: одна - OPTIONS, а другая - POST. Первый - это предварительный запрос, отправленный из браузера, а второй - это фактический запрос, который вы хотите отправить. Предварительный запрос предназначен для того, чтобы убедиться, что у вас есть доступ для запроса ресурсов с сервера.

Как мне это решить

Сервер должен добавить к ответу следующие заголовки: Access-Control-Allow-Origin, Access-Control-Allow-Headers и Access-Control-Allow-Methods. Эти заголовки сообщают браузеру, что вам доверяет владелец сервера, поэтому вы можете запрашивать ресурсы из своего домена. Обратите внимание, что это всего лишь ответ на предполетный запрос. Для фактических запросов POST, которые вы делаете, серверу все равно необходимо добавить в ответ заголовок Access-Control-Allow-Origin. Большинство людей рекомендуют использовать пакет под названием flask-cors. То, что он делает, действует как промежуточное программное обеспечение, которое добавляет некоторые заголовки к вашему ответу, чтобы браузер знал, что сервер доверяет вам, и, таким образом, вы можете запрашивать ресурсы. Однако у меня как-то не получается. Я не изучал его реализации, поэтому не знал причины. Если вы столкнулись с той же проблемой, что и я, вы можете вручную добавить эти заголовки в ответ с помощью всего двух функций:

def build_preflight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add('Access-Control-Allow-Headers', "*")
    response.headers.add('Access-Control-Allow-Methods', "*")
    return response
def build_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response

Если вы хотите увидеть полный исходный код сервера, я поставил работающий сервер Flask:

import requests
from flask import Flask, render_template, request, jsonify, make_response
app = Flask(__name__)
@app.route('/', methods=['OPTIONS','POST'])
def greeting():
    if request.method == 'OPTIONS': 
        return build_preflight_response()
    elif request.method == 'POST': 
        req = request.get_json()
        # query user with req['id']
        # for demonstration, we assume the username to be Eric
        return build_actual_response(jsonify({ 'name': 'Eric' }))
def build_preflight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add('Access-Control-Allow-Headers', "*")
    response.headers.add('Access-Control-Allow-Methods', "*")
    return response
def build_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response
if __name__ == '__main__':
    app.run(host='0.0.0.0')

По умолчанию приложение Flask запускается на порту 5000. Теперь вы можете fetch данные со своего сервера:

import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
  const [username, setUsername] = useState('User'); 
  
  useEffect(() => {
    fetch('http://localhost:5000', {
      method: 'POST', 
      headers: { 'Content-Type': 'application/json' }, 
      body: JSON.stringify({ id:'1234' })
    })
    .then(res => res.json())
    .then(data => { setUsername(data.name) }); 
  })
  
  return (
    <div className="App">
      <h1>{ username }</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Теперь вы должны увидеть имя пользователя, отображаемое на экране, открыв http: // localhost: 3000. Поздравляю!

использованная литература

  1. Веб-документы MDN - Совместное использование ресурсов между источниками (CORS)
  2. Stackoverflow - На запрошенном ресурсе отсутствует заголовок« Access-Control-Allow-Origin - при попытке получить данные из REST API»