Django REST Framework的@action接口返回403而非405问题排查
根本原因
DRF默认的请求处理流程顺序为:
- 路由匹配对应视图类
- 执行用户认证逻辑
- 执行权限校验逻辑
- 匹配请求方法对应的视图方法、校验请求方法是否在允许范围内,该步骤才会为
view.action赋值,若方法不允许则返回405状态码
因此当POST请求访问仅支持GET方法的logout接口时,权限校验先于方法校验执行,此时view.action尚未赋值,自然就会返回403而非预期的405。
解决方案
- 方案1:重写视图集的
initial方法,调整校验顺序
将请求方法匹配和校验逻辑提前到权限校验之前执行,代码示例:
from rest_framework.exceptions import MethodNotAllowed from rest_framework.viewsets import ModelViewSet class UsersViewSet(ModelViewSet): # 原有视图逻辑保持不变 def initial(self, request, *args, **kwargs): # 提前匹配请求对应的action self.action = self.action_map.get(request.method.lower()) if not self.action: raise MethodNotAllowed(request.method) # 执行原有的认证、权限、节流校验逻辑 super().initial(request, *args, **kwargs)
该方案无需修改原有权限逻辑,方法不允许时会直接返回405,符合预期。
- 方案2:修改自定义权限类逻辑
在UsersPermissions权限类的校验逻辑开头,新增action为空的判断,直接抛出方法不允许异常,代码示例:
from rest_framework.exceptions import MethodNotAllowed from rest_framework.permissions import BasePermission class UsersPermissions(BasePermission): def has_permission(self, request, view): if view.action is None: raise MethodNotAllowed(request.method) # 原有权限校验逻辑保持不变 ...
- 方案3:校验请求路径是否匹配
当前通过DefaultRouter注册的users视图集,生成的logout接口路径为/users/logout/,若直接请求/logout/会匹配不到对应action规则,DRF会尝试匹配其他路由,也会导致异常状态码返回,需确保请求路径和路由生成的路径一致。如果需要logout接口直接在根路径,可单独在urlpatterns中添加独立路由配置,限制允许的请求方法即可。
内容的提问来源于stack exchange,提问作者sudden_appearance
相关产品推荐
相关产品推荐

