You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django集成React时遭遇CORS错误,寻求排查解决方法

问题:React + Django 跨域CORS错误(仅特定接口失效)

我用React+Django+PostgreSQL开发时碰到CORS错误,试了多种Django CORS配置都没用,但一个返回“Hi”的简单测试接口能正常工作,不确定问题出在Django视图还是React前端。已经确认VITE_SERVER配置正确,端点也没错。


Django配置

ALLOWED_HOSTS = []

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = [
    'content-type',
    'authorization',
]
CORS_ALLOWED_ALL_ORIGINS = True
ALLOWED_HOSTS = [
    "127.0.0.1",
]

CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"]


AUTH_USER_MODEL = 'customers.CustomerAccount'


# 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',
    'customers',
    'dealer',
    'restful_apis',
]


REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}


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.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

React Fetch钩子

import React from "react";

const useFetch = () => {
  const fetchData = async (endpoint, method, body, token) => {
    const res = await fetch(import.meta.env.VITE_SERVER + endpoint, {
      //   mode: "no-cors",
      method,
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bearer " + token,
      },
      body: JSON.stringify(body),
    });
    const data = await res.json();

    let returnValue = {};
    if (res.ok) {
      if (data.status === "error") {
        returnValue = { ok: false, data: data.msg };
      } else {
        returnValue = { ok: true, data };
      }
    } else {
      if (data?.errors && Array.isArray(data.errors)) {
        const messages = data.errors.map((item) => item.msg);
        returnValue = { ok: false, data: messages };
      } else if (data?.status === "error") {
        returnValue = { ok: false, data: data.message || data.msg };
      } else {
        console.log(data);
        returnValue = { ok: false, data: "An error has occurred" };
      }
    }

    return returnValue;
  };

  return fetchData;
};

export default useFetch;

失效的Django视图

class CarRentalListView(views.APIView):
    authentication_classes = []
    permission_classes = [AllowAny]
    def get(self, request):
        rentals = RentalListing.objects.all()
        serialized_data = []

        for rental in rentals:
            rental_data = RentalListingSerializer(rental).data
            car_data = CarSerializer(rental.car_id).data

            combined_data = {
                "rentallisting_id": rental_data.get("id"),
                "rental_rate": rental_data.get("rental_rate"),
                "drive_to_malaysia": rental_data.get("drive_to_malaysia"),
                "listing_date": rental_data.get("listing_date"),
                "vehicle_id": car_data.get("car_id"),
                "brand": car_data.get("brand"),
                "model": car_data.get("model"),
                "colour": car_data.get("colour"),
                "vehicle_type": car_data.get("vehicle_type"),
                "vehicle_image": car_data.get("vehicle_image"),
                "seat_capacity": car_data.get("seat_capacity"),
            }

            serialized_data.append(combined_data)

        return (Response(serialized_data, status=status.HTTP_200_OK))

正常工作的测试视图

class TestRoute(views.APIView):
    authentication_classes = []
    permission_classes = [AllowAny]

    def get(self, request):
        return Response("Hi")

React调用代码

const Home = () => {
  const fetchData = useFetch();
  const [rentals, setRentals] = useState([]);

  const getRentals = async () => {
    const res = await fetchData("/dealer/cars/rentals", "GET", undefined);
    if (res.ok) {
      setRentals(res.data);
      console.log(res.data);
    } else {
      alert(JSON.stringify(res.data));
      console.log(res.data);
    }
  };

  useEffect(() => {
    getRentals();
    console.log(import.meta.env.VITE_SERVER);
  }, []);

浏览器错误信息

Access to fetch at 'http://127.0.0.1:8000/dealer/cars/rentals' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.


分析与解决方案

核心原因

测试接口正常但目标接口失效,说明CORS配置本身没问题,问题出在目标视图抛出了未被捕获的异常,导致Django在返回错误响应时没有经过corsheaders中间件处理,所以缺少CORS响应头。

排查步骤与修复方案

  1. 修复视图序列化逻辑
    你的视图中手动拼接序列化数据,可能存在以下问题:

    • rental.car_id如果是外键字段,正确引用应为rental.car(外键字段默认是模型名小写,car_id是存储ID的字段),直接传入ID数值会导致CarSerializer序列化失败。
    • 手动拼接数据容易出现字段遗漏或拼写错误,建议改用嵌套序列化器。

    优化后的视图代码:

    from rest_framework.exceptions import APIException
    
    class CarRentalListView(views.APIView):
        authentication_classes = []
        permission_classes = [AllowAny]
        
        def get(self, request):
            try:
                # 预查询关联的Car模型,避免N+1数据库查询问题
                rentals = RentalListing.objects.all().select_related('car')
                # 使用嵌套序列化器返回数据
                serializer = RentalListingWithCarSerializer(rentals, many=True)
                return Response(serializer.data, status=status.HTTP_200_OK)
            except Exception as e:
                # 捕获所有异常,返回带CORS头的错误响应
                return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    

    对应的嵌套序列化器示例:

    class CarSerializer(serializers.ModelSerializer):
        class Meta:
            model = Car
            fields = ["car_id", "brand", "model", "colour", "vehicle_type", "vehicle_image", "seat_capacity"]
    
    class RentalListingWithCarSerializer(serializers.ModelSerializer):
        car = CarSerializer()
        class Meta:
            model = RentalListing
            fields = ["id", "rental_rate", "drive_to_malaysia", "listing_date", "car"]
    
  2. 更新CSRF信任源
    前端运行在http://localhost:5173,需要把该地址加入CSRF_TRUSTED_ORIGINS:

    CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000", "http://localhost:5173"]
    
  3. 验证视图可用性
    直接在浏览器访问http://127.0.0.1:8000/dealer/cars/rentals,确认是否能正常返回JSON数据。如果返回500错误,优先修复视图的逻辑错误,CORS问题会随之解决。


内容的提问来源于stack exchange,提问作者ToXiiXz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:34:57