Django如何像抛出Http404一样抛出Http401与Http403异常(非返回响应)
Hey there! Let's work through this Django API authorization issue you're dealing with. The good news is your approach of using exceptions (like get_object_or_404) is totally valid—you just need to align with how Django handles HTTP exceptions under the hood.
First, Clarify Django's Built-in Exceptions
Django has native support for common HTTP error exceptions, but not all status codes have pre-defined classes out of the box:
Http404(fromdjango.http) works because Django's default exception handler automatically catches it and returns a 404 response.- For 403 Forbidden, Django uses
PermissionDenied(fromdjango.core.exceptions)—this is the built-in exception you should use instead of a customHttp403class, since Django knows how to handle it natively. - There's no built-in
Http401exception, but we can define one and configure Django to handle it properly.
Fix Your Authorization Function
Let's adjust your code to use the right exceptions, plus align the status code logic with standard HTTP practices (401 = missing credentials, 403 = invalid credentials):
from django.core.exceptions import PermissionDenied # Define a custom exception for 401 Unauthorized class Http401(Exception): pass def _check_driver_authorization(request): auth_token = request.headers.get('authorization') # No authorization header provided → 401 Unauthorized if not auth_token: raise Http401("Authorization header is required to access this resource") # Token exists but doesn't match any driver → 403 Forbidden driver = Driver.objects.filter(access_token=auth_token).first() if not driver: raise PermissionDenied("Invalid or expired access token") # Attach the valid driver to the request for use in views request.driver = driver
Configure Django to Handle the Custom Http401 Exception
Since Http401 is custom, we need to tell Django how to convert it into a proper HTTP response. Add this to your project's urls.py:
from django.http import HttpResponseUnauthorized def custom_401_handler(request, exception): # Return a JSON response (ideal for APIs) with the error message return HttpResponseUnauthorized({"error": str(exception)}) # Register the handler for 401 errors handler401 = custom_401_handler
Why Your Original Custom Http403 Failed
Django's default exception handler only recognizes a specific set of built-in exceptions (like Http404 and PermissionDenied). When you threw a custom Http403 exception, Django didn't know how to map it to a 403 response—hence the issues you saw. Using PermissionDenied eliminates this problem entirely.
Bonus: If You're Using Django REST Framework (DRF)
If you're building APIs with DRF, you can simplify this even more by using DRF's built-in authentication/permission classes. DRF automatically handles 401/403 responses for you, so you don't have to write custom exception handlers:
from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView from rest_framework.response import Response class DriverAPIView(APIView): authentication_classes = [TokenAuthentication] permission_classes = [IsAuthenticated] def get(self, request): # Your view logic here—DRF already handled auth checks return Response({"message": "Authorized driver access"})
内容的提问来源于stack exchange,提问作者wassim chaguetmi

