使用 React 调用 REST API 时出现 CORS 错误

IT技术 django rest reactjs cors django-rest-framework
2021-04-22 01:21:24

我创建了一个带有 django-rest-framework 的restful api,可以通过这个 URL http://192.168.33.10:8002/scenarios/访问,我正在创建一个 React 应用程序来调用 api 并使用它的数据。

我正在使用 fetch 调用 api

componentWillMount: function(){
 this.setState({Problemstyle: this.props.Problemstyle})
 fetch('http://192.168.33.10:8002/scenarios/')
 .then(result=>result.json())
 .then(result=> {
   this.steState({items:result})
 })
 },

当我运行我的应用程序时,我的浏览器出现错误

Fetch API 无法加载http://192.168.33.10:8002/scenarios/请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问源“ http://192.168.33.10:8001 ”。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。

我不确定如何解决这个问题,因为我刚刚开始使用 React

4个回答

通过安装 django-cors-headers pip install django-cors-headers

然后,添加已安装的应用程序“corsheaders”。

添加设置,

CORS_ORIGIN_ALLOW_ALL = True

和,

ALLOWED_HOSTS = ['*']

这应该可以解决问题。

更新

您还需要将其添加到中间件中,

MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]
您是否在 installed_apps 中添加了“corsheaders”?更新了答案
2021-05-24 01:21:24
我还需要在 js 上做些什么吗??我正在使用 axios。
2021-06-01 01:21:24
不要为请求传递任何自定义标头,除此之外没有什么可打扰的。
2021-06-08 01:21:24
错误还是一样??检查您的设置是否被正确提供,并确保没有任何内容被覆盖。
2021-06-12 01:21:24
这是昨天的工作。今天,当我再次尝试时,它不起作用。有什么建议
2021-06-20 01:21:24

当前接受的答案可能会使网站面临安全风险:

为什么会发生错误:

为了让您的 AJAX 请求正常工作,需要做两件事:

  1. 服务器必须接受请求。
  2. 返回的请求必须被浏览器接受,以便客户端可以对其进行处理。

OP 报告的错误表明此过程的第二部分失败。这是因为如果请求是从与返回请求的服务器不同的域发送的,浏览器将不会接受它,除非设置了适当的标头(即,服务器已授予浏览器读取它的权限)。

如何修复:

现在要解决这个问题,我们可以使用django-cors-headers. 这将添加适当的标头,以便浏览器接受返回的响应。要安装运行:

pip install django-cors-headers

并将其添加到您的中间件中:

MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]

现在,您需要将发送 AJAX 请求的域添加到允许域列表中:

CORS_ALLOWED_ORIGINS = [
    "www.example.com",
    "http://127.0.0.1:8000",
    ...
]

怎么样CORS_ORIGIN_ALLOW_ALL

除非您有特殊需要,否则不要使用它。将此设置为 true,将意味着任何来源都可以向您的 API 发出请求,并获得响应。除非您正在制作公共 API,否则您可能不需要这样做。更有可能您只需要为单个域或几个域提供服务(也许您有一个前端,从不同的地方提供给您的 API 等)

如果你幸福的任何域名访问你的API,那么你可以设置如下:

CORS_ORIGIN_ALLOW_ALL = True

如果您这样做,您还需要设置以下内容:

ALLOWED_HOSTS = ['*']

这样做的原因是 Django 默认只接受某些主机,所以没有意义设置,CORS_ORIGIN_ALLOW_ALL = True除非你真的要接受任何人的请求(这是上面解释的第 1 部分)。

请注意,通过将允许的主机设置为通配符,您将面临 HTTP 主机标头攻击。确保您了解这些,并确保您不受影响。您可以在 django 文档中阅读有关它们的更多信息

另请注意:如果您没有设置您的ALLOWED_HOSTS并且想知道为什么您的请求有效,那是因为当DEBUG=True某些主机被自动允许时,http://127.0.0.1:8000等等。

使用 django-cors-headers

首先使用 pip 安装 django-cors-headers

pip install django-cors-headers

您需要将其添加到您的项目 settings.py 文件中:

INSTALLED_APPS = (
    ##...
    'corsheaders'
)

接下来需要将 corsheaders.middleware.CorsMiddleware 中间件添加到 settings.py 中的中间件类中

MIDDLEWARE_CLASSES = (
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.BrokenLinkEmailsMiddleware',
    'django.middleware.common.CommonMiddleware',
    #...
)

然后,您可以通过添加以下设置为所有域启用 CORS

CORS_ORIGIN_ALLOW_ALL = True

或者 只为指定域启用 CORS:

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    'http//:localhost:8000',
)

我想提出一个不需要改变 Django 或 React 应用程序行为的解决方案。

在生产中,您可能希望在同一个域/来自同一个服务器的不同路径下为两个应用程序提供服务。这不会在生产中导致任何 CORS 冲突。

当然,我们想调试 Django 并在调试时使用 React HMR 和 Dev 工具。为此,我启动了一个 nginx docker 容器:

docker-compose.yml

version: '3.8'

services:
  web:
    image: nginx:latest
    ports: 
      - 8080:80
    volumes: 
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    command: [nginx-debug, '-g', 'daemon off;']
    environment:
    - NGINX_HOST=localhost
    - NGINX_PORT=80

nginx.conf

Django 调试在端口 8000 上,React HMR 在端口 3000 上。我已经允许三个路径去 Django 应用程序/accounts/api、 和/admin其余的进入 React 应用程序(并进入 React Router 系统)

events {}
http{
    server {
        listen      80;
        server_name localhost;
        location ~* /(accounts|api|admin) {
            proxy_pass      http://host.docker.internal:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
        location / {
            proxy_pass      http://host.docker.internal:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

之后docker-compose up,,manage.py runservernpm start,这两个应用程序都可以在localhost:8000