当我从 LAN 上的另一台 PC 浏览时,我的 ReactJS/Django(Rest API) 提示 Unhandled Promise 拒绝

Posted

技术标签:

【中文标题】当我从 LAN 上的另一台 PC 浏览时,我的 ReactJS/Django(Rest API) 提示 Unhandled Promise 拒绝【英文标题】:My ReactJS/Django(Rest API) prompts an Unhandled Promise rejection when I browse from a different PC on the LAN 【发布时间】:2021-07-25 13:31:40 【问题描述】:

虽然我可以看到前端表单,但如果我尝试提交控制台会显示:“Fetch API 无法加载 http://localhost:8000/api/task-create/ 由于访问控制检查。” 下一行是:“加载资源失败:无法与服务器建立连接。”

这是我在我的电脑上看到的,(这没问题,每个功能都能完美运行)

这就是我在连接到同一个 LAN 的另一台 PC 上得到的

我认为它与标头和CORS,Django REST框架身份验证有关,我都尝试过但似乎不起作用。

有什么提示吗?

这是我的 settings.py:

Django settings for todoapp project.

Generated by 'django-admin startproject' using Django 3.2.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-whh5g$8**@u4t1m%13=c$6!k-5#o0jwhr&&7i7^d$ky%$ku+ls'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'api.apps.ApiConfig'
]

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

ROOT_URLCONF = 'todoapp.urls'

TEMPLATES = [
    
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'frontend/build')
        ],
        'APP_DIRS': True,
        'OPTIONS': 
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        ,
    ,
]

WSGI_APPLICATION = 'todoapp.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = 
    'default': 
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    



# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    ,
    
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    ,
    
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    ,
    
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    ,
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, javascript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'frontend/build/static')
]

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

CORS_ALLOWED_ORIGINS = [
    "http://192.168.0.6:3000",
]

我的意见.py:

from django.shortcuts import render
from django.http import JsonResponse

from rest_framework.decorators import api_view
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializers import TaskSerializer

from .models import Task

# Create your views here.
@api_view(['GET'])
def apiOverview(request):
    api_urls = 
        'List':'task-list/',
        'Detail View':'/task-detail/<str:pk>',
        'Create':'/task-create/',
        'Update':'task-update/<str:pk>',
        'Delete':'task-delete/<str:pk>', 
    
    return Response(api_urls)

@api_view(['GET'])
def taskList(request):
    tasks = Task.objects.all()
    serializer = TaskSerializer(tasks, many=True)
    return Response(serializer.data)

@api_view(['GET'])
def taskDetail(request, id):
    task = Task.objects.get(id=id)
    serializer = TaskSerializer(task, many=False)
    return Response(serializer.data)

@api_view(['POST'])
def taskCreate(request):
    serializer = TaskSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
    return Response(serializer.data)    

@api_view(['POST'])
def taskUpdate(request, id):
    task = Task.objects.get(id=id)
    serializer = TaskSerializer(instance=task, data=request.data)
    if serializer.is_valid():
        serializer.save()
    return Response(serializer.data)

@api_view(['DELETE'])
def taskDelete(request, id):
    task = Task.objects.get(id=id)
    task.delete()
    return Response('Task succesfully deleted!')

和我的 react 主组件 App.js:

import React from "react"
import './App.css';
import TodoItem from "./TodoItem"
import Form from "./Form"


class App extends React.Component 
  constructor(props)
    super(props)
    this.state = 
      todoList:[],
      activeItem:
        id:null,
        title:'',
        completed:false,
      ,
      editing:false,
    
    this.fetchTasks = this.fetchTasks.bind(this)
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
    this.getCookie = this.getCookie.bind(this)
    this.handleEdit = this.handleEdit.bind(this)
    this.handleDelete = this.handleDelete.bind(this)
    this.handleCompleted = this.handleCompleted.bind(this)
  

  getCookie(name) 
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') 
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) 
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) 
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            
        
    
    return cookieValue;
  

  componentDidMount()
    this.fetchTasks()
  

  fetchTasks()
    fetch('http://localhost:8000/api/task-list/')
    .then(response => response.json())
    .then(data =>
            this.setState(
              todoList: data
            )
      )
  

  handleChange(event)
    let value = event.target.value
    this.setState(
      activeItem: 
        ...this.state.activeItem,
        title: value
      
    )
  

  handleSubmit(event)
      event.preventDefault()
      let csrftoken = this.getCookie('csrftoken') 
      let url='http://localhost:8000/api/task-create/'
      if(this.state.editing === true)
        url=`http://localhost:8000/api/task-update/$this.state.activeItem.id/`  
        this.setState(
          editing: false
        )
       
      fetch(url,
      method: 'POST',
      headers:
        'Content-type':'application/json',
        'X-CSRFToken': csrftoken,
        ,
      body: JSON.stringify(this.state.activeItem)
      ).then(()=>
        this.fetchTasks()
        this.setState(
          activeItem:
            id:null,
            title:'',
            completed:false,
          
        )
      ).catch((e)=>
        console.log('ERROR:',e)
      )
  

  handleEdit(todo)
    this.setState(
      activeItem: todo,
      editing: true,
    )
  

  handleDelete(todo)
    let csrftoken = this.getCookie('csrftoken')
    let url = `http://localhost:8000/api/task-delete/$todo.id/`
    fetch(url, 
      method: 'DELETE',
      headers: 
        'Content-type': 'application/json',
        'X-CSRFToken': csrftoken
      
    ).then((response)=>
      this.fetchTasks()
    ).catch((error)=>
      console.log('ERROR:',error)
    )
  

  handleCompleted(todo)
    let csrftoken = this.getCookie('csrftoken')
    const url=`http://localhost:8000/api/task-update/$todo.id/`
    todo.completed= !todo.completed
    fetch(url,
      method:'POST',
      headers:
        'Content-type': 'application/json',
        'X-CSRFToken': csrftoken
      ,
      body: JSON.stringify(
        title:todo.title,
        completed:todo.completed,)
    ).then(()=>
      this.fetchTasks()
    ).catch((e)=>
      console.log('ERROR:',e)
    )
  

  render()
    let todoItems = this.state.todoList.map((todo, id)=> 
      return( 
        <TodoItem 
          key=id todo=todo 
          onClick=()=> this.handleEdit(todo) 
          onDelete=()=> this.handleDelete(todo)
          onCompleted=()=> this.handleCompleted(todo)
        />
      ) 
    )
    return(
      <div className="container">
          <div id="task-container">
              <Form 
                onChange=this.handleChange 
                onSubmit=this.handleSubmit 
                data=this.state.activeItem
              />
              <div id="list-wrapper">
                todoItems 
              </div>  
          </div>
      </div>
    )
      


export default App;

感谢您的帮助...

【问题讨论】:

【参考方案1】:

您的 IP 地址可能有问题。比如,这台不同的计算机可能有一个激活的 *** 或任何其他指向其他 IP 地址而不是 localhost 的问题。

所以,在你的 django settings.py 中尝试改变这个:

CORS_ALLOWED_ORIGINS = [
    "http://192.168.0.6:3000",
]

对这种方法:

CORS_ORIGIN_WHITELIST = [
     'http://localhost:3000',
]

或者如果你想允许所有:

CORS_ORIGIN_ALLOW_ALL = True # If you use this approach then `CORS_ORIGIN_WHITELIST` will not have any effect
CORS_ALLOW_CREDENTIALS = True

并检查它是否有效。

【讨论】:

以上是关于当我从 LAN 上的另一台 PC 浏览时,我的 ReactJS/Django(Rest API) 提示 Unhandled Promise 拒绝的主要内容,如果未能解决你的问题,请参考以下文章

从网络上的另一台电脑访问 ASP.NET 开发服务器

在另一台 PC 上出现错误消息“禁止您无权访问 / 在此服务器上”

您无权访问此服务器上的 /phpmyadmin/。在 Windows 7 中访问另一个 pc localhost

从另一个网络上的另一台计算机访问 db 时出现错误 #1045

使 WordPress 站点可以从 LAN 内部和外部访问

从网络中的另一台计算机连接到 localhost