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

如何解决JS Fetch向Django REST API发起POST请求的400错误

问题原因

报错的核心是请求头的Content-Type与请求体格式不匹配:
你在fetch请求里手动设置了Content-Type: application/json,但请求体传入的是FormData对象——FormData默认使用multipart/form-data编码格式,而非JSON。服务器收到这种混合格式的请求后,尝试按JSON解析就会失败,抛出"JSON parse error"。

另外还有一个潜在问题:BookingForm包含client字段,但前端表单大概率没有传递这个值(正常逻辑下应该自动关联当前登录用户),即使解决了JSON问题,后续也可能因缺少client字段导致请求失败。

解决方案

方案1:将FormData转为JSON格式发送

修改JS代码,把FormData转换为普通对象后序列化为JSON字符串,保持Content-Type为application/json:

csrf = document.getElementsByName("csrfmiddlewaretoken")[0].value;
const formdata = new FormData(form);
// 将FormData转为普通对象
const dataObj = {};
formdata.forEach((value, key) => {
    dataObj[key] = value;
});

fetch('/api/booking/', {
    method: 'POST',
    headers: {
        "X-CSRF-Token": csrf,
        "Content-Type": "application/json"
    },
    credentials: "same-origin",
    body: JSON.stringify(dataObj)
})
.then(res => res.json())
.then(data => console.log(data));

方案2:使用FormData默认的multipart/form-data格式

去掉手动设置的Content-Type,fetch会自动为FormData设置正确的multipart/form-data请求头(包含boundary参数),DRF序列化器可直接解析这种格式:

csrf = document.getElementsByName("csrfmiddlewaretoken")[0].value;
const formdata = new FormData(form);

fetch('/api/booking/', {
    method: 'POST',
    headers: {
        "X-CSRF-Token": csrf,
        // 移除Content-Type设置,让fetch自动处理
    },
    credentials: "same-origin",
    body: formdata
})
.then(res => res.json())
.then(data => console.log(data));

处理client字段的潜在问题

client是关联User的外键,不应该让前端传递(避免篡改),建议在后端视图自动设置当前登录用户:
修改BookingView类,添加perform_create方法:

from rest_framework.permissions import IsAuthenticated

class BookingView(generics.ListCreateAPIView):
    queryset = Booking.objects.all()
    serializer_class = BookingSerializer
    # 限制仅登录用户可创建预订
    permission_classes = [IsAuthenticated]

    def perform_create(self, serializer):
        # 将当前登录用户设为预订的client
        serializer.save(client=self.request.user)

同时修改BookingForm和序列化器,移除前端不需要传递的client字段:

# forms.py
class BookingForm(ModelForm):
    class Meta:
        model = Booking
        fields = ['date', 'hour']  # 移除client字段

# 对应的BookingSerializer示例
class BookingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Booking
        fields = ['id', 'date', 'hour', 'client']  # 返回时可保留client,创建时无需前端传入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:08:37