在使用Django Rest Framework的ModelViewSet调用函数时出现跨域错误(Cors error)。

huangapple go评论69阅读模式
英文:

Getting Cors error when calling functions from ModelViewSet in Django Rest Framework

问题

这是我的Django项目中的一个奇怪错误。我使用Django和Django Rest Framework创建了一个应用,其中包含一个ModelViewSet,用于为我的Race资源创建CRUD端点。

race.py

from ..models.race import Race
from ..serializers.race import RaceSerializer
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated

class RaceViewSet(ModelViewSet):
    model = Race
    serializer_class = RaceSerializer
    queryset = Race.objects.all()

这是我的应用的urls.py

from django.urls import path, include
from rest_framework import routers

from .views.race import RaceViewSet
from .views.test import TestView

router = routers.DefaultRouter()
router.register(r'races', RaceViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('test', TestView.as_view(), name='test'),
]

我已经正确设置了一切,并且可以使用Postman访问列表方法而没有问题。

现在我知道CORS问题在Postman中不会发生,并且安装了'django-cors-headers'来解决我的Angular应用中的CORS问题。

settings.py

ALLOWED_HOSTS = []

CORS_ORIGIN_WHITELIST = [
    'http://localhost:4200', # 我的Angular服务器
]

# 应用程序定义

INSTALLED_APPS = [
    ...
    'rest_framework', 
    'corsheaders',
    ..
]

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

而且它起作用了,我创建了一个测试路由来检查一切,并且在我的Angular应用程序中调用了该方法。

这是测试ViewSet

from rest_framework.views import APIView
from rest_framework.response import Response
from ..models.race import Race
from ..serializers.race import RaceSerializer

class TestView(APIView):
    def get(self, request): # 我复制了列表方法应该在理论上执行的操作。
        races = Race.objects.all()
        serializer = RaceSerializer(races, many=True)
        return Response(serializer.data)

home.component.ts

test(): void {
    const url = 'http://127.0.0.1:8000/api/v1/rpg/test'; // 这次我调用了测试url
    
    // 发送HTTP POST请求
    this.http.get(url).subscribe(
        {
            next: (response) => {
                // 处理成功的注册
                console.log('SUCCESS', response);
            },
            error: (failResponse) => {
                // 处理注册错误
                console.error('Sign-in error:', failResponse);
            },
            complete: () => {
                console.log('Test completed:');
            }
        }
            
    );
}

当然,为了双重检查CORS中间件是否实际工作,我从settings.py中删除了中间件,然后再次尝试测试路由,正如所期望的那样,我得到了CORS错误,但是再次添加中间件使测试路由正常工作。

但是,当尝试访问ModelViewSet上定义的路由,特别是列表时,无论是否使用中间件,我都会遇到CORS错误。

home.component.ts

test(): void {
    const url = 'http://127.0.0.1:8000/api/v1/rpg/races'; // 这次尝试访问赛车列表
    
    // 发送HTTP POST请求
    this.http.get(url).subscribe(
        {
            next: (response) => {
                // 处理成功的注册
                console.log('SUCCESS', response);
            },
            error: (failResponse) => {
                // 处理注册错误
                console.error('Sign-in error:', failResponse);
            },
            complete: () => {
                console.log('Test completed:');
            }
        }
            
    );
}

在控制台上我得到了这个错误。

"Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/v1/rpg/races' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."

再次强调,我确信路由正常工作,我在Postman中尝试过没有问题,所以我有点一头雾水,希望你们能帮助我。

编辑 -

奇怪的是,POST方法似乎工作正常 :/,我仍然在尝试GET方法时遇到CORS错误。

home.component.ts

test(): void {
    const url = 'http://127.0.0.1:8000/api/v1/rpg/races/'; 
    
    let body = {
        "name": "Lowlander",
        "hp_growth": 1.9,
        "mp_growth": 1.1,
        "str_growth": 1.7,
        "int_growth": 1.2,
        "dex_growth": 1.3,
        "base_hp": 150,
        "base_mp": 100,
        "base_str": 85,
        "base_int": 70,
        "base_dex": 75
    }
    // 发送HTTP POST请求
    this.http.post(url,body).subscribe(
        {
            next: (response) => {
                // 处理成功的注册
                console.log('SUCCESS', response);
            },
            error: (failResponse) => {
                // 处理注册错误
                console.error('Sign-in error:', failResponse);
            },
            complete: () => {
                console.log('Test completed:');
            }
        }
            
    );
}
英文:

This error is pretty odd, I have a project on Django with Django Rest Framework and I have an app with a ModelViewSet to create CRUD endpoints for my Race resource.

race.py

from ..models.race import Race
from ..serializers.race import RaceSerializer
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated

class RaceViewSet(ModelViewSet):
    model = Race
    serializer_class = RaceSerializer
    queryset = Race.objects.all()


This is my app's urls.py

from django.urls import path, include
from rest_framework import routers


from .views.race import RaceViewSet
from .views.test import TestView


router = routers.DefaultRouter()
router.register(r'races', RaceViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('test', TestView.as_view(), name='test'),
]

I got everything set correctly, and I can access the list method without issues using Postman

Now Im aware of the CORS issue doesn't happen in Postman and installed 'django-cors-headers' to solve the CORS issue on my Angular app.

settings.py

ALLOWED_HOSTS = []

CORS_ORIGIN_WHITELIST = [
    'http://localhost:4200', # My angular server
]

# Application definition

INSTALLED_APPS = [
    ...
    'rest_framework', 
    'corsheaders',
    ..
]

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

And it works, I made a test route to check everything and inside my angular app I called that method

this is the test ViewSet

from rest_framework.views import APIView
from rest_framework.response import Response
from ..models.race import Race
from ..serializers.race import RaceSerializer

class TestView(APIView):
    def get(self, request): # I copied what the list method should in theory do.
        races = Race.objects.all()
        serializer = RaceSerializer(races, many=True)
        return Response(serializer.data)

home.component.ts

test(): void {
        const url = 'http://127.0.0.1:8000/api/v1/rpg/test'; // This time Im calling the test url
        
        // Send the HTTP POST request
        this.http.get(url).subscribe(
            {
                next: (response) => {
                    // Handle successful sign-up
                    console.log('SUCCESS', response);
                },
                error: (failResponse) => {
                    // Handle sign-up error
                    console.error('Sign-in error:', failResponse);
                },
                complete: () => {
                    console.log('Test completed:');
                }
            }
                
        );
    }

Of course just to double check if the CORS middleware was actually working I removed the middleware from settings.py and tried the test route again and as espected I got the CORS error, but putting the middleware again made the test route work just fine.

But when trying to access the routes defined on my ModelViewSet, particularly the list Im getting a CORS error with or without the middleware

home.component.ts

test(): void {
        const url = 'http://127.0.0.1:8000/api/v1/rpg/races'; // Trying to access the races list this time
        
        // Send the HTTP POST request
        this.http.get(url).subscribe(
            {
                next: (response) => {
                    // Handle successful sign-up
                    console.log('SUCCESS', response);
                },
                error: (failResponse) => {
                    // Handle sign-up error
                    console.error('Sign-in error:', failResponse);
                },
                complete: () => {
                    console.log('Test completed:');
                }
            }
                
        );
    }

And Im getting this error on console.

"Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/v1/rpg/races' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."

Again, Im sure the route works fine, I tried it in Postman without issues, so Im kinda in the dark here, I hope you guys can help me

EDIT--

Oddly enough, the POST method seems to be working just fine :/, Im still struggling with the GET method

home.component.ts

test(): void {
        const url = 'http://127.0.0.1:8000/api/v1/rpg/races/'; 
        
        let body = {
            "name": "Lowlander",
            "hp_growth": 1.9,
            "mp_growth": 1.1,
            "str_growth": 1.7,
            "int_growth": 1.2,
            "dex_growth": 1.3,
            "base_hp": 150,
            "base_mp": 100,
            "base_str": 85,
            "base_int": 70,
            "base_dex": 75
        }
        // Send the HTTP POST request
        this.http.post(url,body).subscribe(
            {
                next: (response) => {
                    // Handle successful sign-up
                    console.log('SUCCESS', response);
                },
                error: (failResponse) => {
                    // Handle sign-up error
                    console.error('Sign-in error:', failResponse);
                },
                complete: () => {
                    console.log('Test completed:');
                }
            }
                
        );
    }

答案1

得分: 0

尝试使用这个:

CORS_ALLOWED_ORIGINS = [
'http://localhost:4200'
]
英文:

Try with this:

CORS_ALLOWED_ORIGINS = [
'http://localhost:4200'
]

答案2

得分: 0

我是个白痴,问题是我需要在路由的末尾添加一个 /

使用这个URL它就可以正常工作:':)'

const url = 'http://127.0.0.1:8000/api/v1/rpg/races/';
英文:

Im an idiot, the issue was that I needed to add a / at the end of the route

with this url it works just fine :')

const url = 'http://127.0.0.1:8000/api/v1/rpg/races/';

huangapple
  • 本文由 发表于 2023年6月22日 17:44:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76530579.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定