【问题标题】:CORS error while consuming calling REST API with React使用 React 调用 REST API 时出现 CORS 错误
【发布时间】:2017-10-17 15:52:05
【问题描述】:

我创建了一个带有 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”标头。因此,不允许访问 Origin 'http://192.168.33.10:8001'。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

我刚刚开始使用 React,不知道如何解决这个问题

【问题讨论】:

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


【解决方案1】:

通过pip install django-cors-headers安装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',
    ...
]

【讨论】:

  • 这是昨天的工作。今天,当我再次尝试时,它不起作用。任何建议
  • 报错还是一样??检查您的设置是否正确提供,并确保没有任何内容被覆盖。
  • 我也需要在js上做点什么吗??我正在使用 axios。
  • 不要为请求传递任何自定义标头,除此之外没有什么可担心的。
  • 您是否在 installed_apps 中添加了“corsheaders”?更新了答案
【解决方案2】:

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

为什么会发生错误:

为了让您的 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 主机标头攻击。确保您了解这些,并确保您不受影响。你可以阅读更多关于他们的信息in the django docs

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

【讨论】:

    【解决方案3】:

    使用 django-cors-headers

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

    pip install django-cors-headers
    

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

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

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

    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',
    )
    

    【讨论】:

      【解决方案4】:

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

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

      当然,我们想调试 Django 并在调试时使用 React HMR 和开发工具。为此,我创建了一个 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 upmanage.py runservernpm start 之后,这两个应用程序都可以在localhost:8000 获得!

      【讨论】:

        猜你喜欢
        • 2019-07-05
        • 2020-09-07
        • 2016-06-10
        • 2020-01-31
        • 1970-01-01
        • 2020-06-17
        • 2020-01-21
        • 1970-01-01
        • 2015-04-10
        相关资源
        最近更新 更多