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

React Service Worker无法向Django服务器上传Blob文件求助

问题排查与解决方案

核心问题分析

你遇到的两个错误本质上是两个关联问题:手动设置Content-Type导致后端解析失败,以及Service Worker传递/后端接收Blob时的流程错误。


1. 解决Content-Type: multipart/form-data导致的400错误

当使用FormData作为fetch请求的body时,绝对不要手动设置Content-Type: multipart/form-data。浏览器会自动生成包含boundary分隔符的正确请求头(比如multipart/form-data; boundary=----WebKitFormBoundaryxxxx),手动设置会覆盖这个自动生成的头,导致后端无法正确解析多部分表单数据,直接返回400。

修改background-worker.js中的请求头部分:

const headers = new Headers({
    'Authorization': `Token ${authToken}`,
    // 移除手动设置的Content-Type
});

2. 解决Blob字段为空的问题

去掉Content-Type后Blob仍为空,需要从前端传递、后端接收两个环节排查:

前端环节:确认Blob传递与FormData构建

  • 在Service Worker的message事件中,检查接收到的blob是否为有效对象:
    this.addEventListener('message', async (event) => {
        const data = event.data;
        if (data.blob) {
            console.log('Received Blob:', data.blob.size, data.blob.type); // 确认size>0、type正确
            // ...后续逻辑
        }
    });
    
  • 确保FormData.append('blob', file)中的file是有效File对象:
    const file = new File([blob], fileName, { type: blob.type });
    console.log('Created File:', file.size); // 确认文件大小正常
    

后端环节:修复ViewSet与Serializer的错误

你的ExerciseRecordViewSet的perform_create方法存在逻辑错误,违背了ModelViewSet的工作流程,可能导致文件解析失败:

  • perform_create不需要手动创建Serializer并返回Response,父类已经处理了请求验证、序列化、响应的流程
  • 直接操作request.data容易引发未验证的错误,应该使用serializer.validated_data

修改后的perform_create:

from django.utils import dateformat

class ExerciseRecordViewSet(viewsets.ModelViewSet):
    queryset = ExerciseRecord.objects.all()
    serializer_class = ExerciseRecordSerializer

    # ...保留get_queryset方法...

    def perform_create(self, serializer):
        # 从已验证的序列化数据中获取值
        patient = serializer.validated_data['patient']
        date = serializer.validated_data['date']

        # 查询患者的所有关联训练ID
        patient_exercises_ids = [
            pe.exercise.id for pe in PatientExercise.objects.filter(patient=patient)
        ]
        # 查询今日已完成的训练ID
        today_completed_exercise_ids = [
            er.exercise.id for er in ExerciseRecord.objects.filter(date=date, patient=patient)
        ]

        # 判断是否完成所有训练
        if set(patient_exercises_ids) == set(today_completed_exercise_ids):
            patient.completed_exercise_date = date.today()
            patient.save()

        # 调用父类方法保存数据
        serializer.save()

同时检查你的ExerciseRecordSerializer,确保blob字段正确配置为FileField:

from rest_framework import serializers
from .models import ExerciseRecord

class ExerciseRecordSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExerciseRecord
        fields = ['id', 'patient', 'exercise', 'date', 'video', 'review', 'commment', 'blob']
        # 外键字段默认会用PrimaryKeyRelatedField,无需额外配置

最终验证步骤

  1. 前端移除手动Content-Type头后,重新发送请求
  2. 后端控制台查看request.data,确认blob字段不再是None
  3. 检查Django媒体目录(exercise_records/)是否生成了上传的文件

内容的提问来源于stack exchange,提问作者Tejas Vaij

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:22:11