问题现象
删除接口调用成功,但前端读取不到响应体中的 message 或 result,于是把成功操作显示成失败。
根本原因
DRF 的 ModelViewSet 删除操作默认返回 204 No Content。按照 HTTP 语义,204 响应不包含响应体;浏览器的 fetch、Axios 等客户端不会提供可供业务代码读取的响应体。
Postman 等调试工具有时会展示服务端实际发出的原始字节,但这不代表 204 响应可以携带业务响应体,也不应依赖这种行为。
renderer_classes = [JSONRenderer]本身不是问题原因。关键在于 DRF 的删除操作返回了 204,而调用方却期待 JSON 响应体。
方案一:保留 204,前端检查状态码
如果接口采用标准的无内容删除响应,前端应根据 HTTP 状态判断成功,而不是检查响应体:
const response = await axios.delete(`/api/books/${id}/`)
if (response.status === 204) {
// 删除成功
}
方案二:需要返回 JSON 时使用 200
如果 API 合约要求返回消息或业务字段,可以重写 destroy 并返回 200:
from rest_framework import status, viewsets
from rest_framework.response import Response
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(
{"message": "删除成功", "result": True},
status=status.HTTP_200_OK,
)
经验总结
- 选择 204 时,接口不应返回响应体,客户端应检查状态码。
- 如果客户端必须读取 JSON,就使用 200 等允许包含响应体的状态码,并保持前后端接口合约一致。
- 用 Postman 测试后,还应使用实际浏览器客户端验证行为。
Yoleo
正在构建