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

Angular中FormData提交API报错ID缺失,请求排查

问题排查:提交FormData时API提示ID缺失

我尝试将JSON对象转换为FormData,通过convertJsonToFormData函数处理后调用服务提交,但API抛出错误提示ID缺失。已传入TrainingProviderId,理论上应可正常提交,请帮忙排查,如需更多信息我会补充。

相关代码

组件代码

// In component 
async addQuestion(position, status) {
  const questionDetails = {
    groupId: this.myForm.value.quesType === 3 ? this.myForm.value.groupId : null,
    isOMR: this.myForm.value.quesType === 1 ? 1 : 0,
    complexity: this.myForm.value.complexity,
    questionType: this.myForm.value.quesType,
    questionDescription: this.myForm.value.question.trim(),
    questionHint: this.myForm.value.questionHint.trim(),
    option1: this.myForm.value.optionA.trim() || this.optionAImg.file,
    option2: this.myForm.value.optionB.trim() || this.optionBImg.file,
    option3: this.myForm.value.optionC.trim() || this.optionCImg.file,
    option4: this.myForm.value.optionD.trim() || this.optionDImg.file,
    answer: this.myForm.value.answer,
    answerFormat: null,
    descriptiveAnswer: this.myForm.value.answerDescription.trim(),
    questionFilePath: '',
    option1FilePath: '',
    option2FilePath: '',
    option3FilePath: '',
    option4FilePath: '',
    answerFilePath: '',
    descriptiveAnswerExplanation: null,
    examOrCourseId: null,
    SectionId: this.myForm.value.section,
    SubsectionId: this.myForm.value.subSection,
    trainingProviderId: this.trainingProviderId,
  };
  if (this.myForm.value.quesType !== 1) {
    questionDetails.questionFilePath = '';
    questionDetails.option1FilePath = '';
    questionDetails.option2FilePath = '';
    questionDetails.option3FilePath = '';
    questionDetails.option4FilePath = '';
    questionDetails.answerFilePath = '';
    questionDetails.option1 = '';
    questionDetails.option2 = '';
    questionDetails.option3 = '';
    questionDetails.option4 = '';
  }
  if (this.myForm.value.quesType === 3) {
    questionDetails.descriptiveAnswer = '';
    questionDetails.answer = '';
  }
  const formData = this.convertJsonToFormData(questionDetails);

  this.questionBankService.createQuestion(formData, this.trainingProviderId).subscribe(
    (res) => {
      if (res.status === 'Success') {
        this.toastr.success(this.translate.instant('question_bank.success.create_question'),
          this.translate.instant('question_bank.success.title'));
        this.router.navigate(['/pages/training-provider/question-bank']);
      } else {
        const index = 1;
        this.toastr.show('Error', `Toast ${index}`, { position, status });
      }
    },
    (err) => {
      if (err) {
        this.toastr.danger(this.translate.instant('question_bank.errors.create_question'),
          this.translate.instant('question_bank.errors.create_question_title'));
      }
    },
  );
}
convertJsonToFormData(jsonData): FormData {
  const formData = new FormData();
  for (const key in jsonData) {
    if (Object.prototype.hasOwnProperty.call(jsonData, key)) {
      const value = jsonData[key];

      if (value instanceof File) {
        formData.append(key, value, value.name);
      } else {
        formData.append(key, value);
      }
    }
  }
  return formData;
}

服务代码

// In service
createQuestion(form: FormData, trainingProviderId: string) {
  const userObject = this.authService.getUser();
  const headers = new HttpHeaders();
  headers.append('Authorization', `Bearer ${userObject.token}`);
  headers.append('Content-Type', 'multipart/form-data');
  headers.append('Accept', 'application/json');
  const options = { headers };
  const API_URL = `htttps://server_address/api/company/${trainingProviderId}/question`;
  return this.httpClient.post<unknown>(API_URL, form, options).pipe(
    map((data: {status: string}) => data),
    catchError((error) => throwError(() => error)),
  );
}

排查方向

  • URL拼写错误:服务中的API_URL写为htttps://server_address/...,多了一个t,正确应为https。错误的协议会导致请求无法正确到达目标服务器,或者后端路由无法解析路径中的trainingProviderId,进而触发ID缺失的错误提示。
  • trainingProviderId实际值为空:确认组件中的this.trainingProviderId是否真的有有效值(非空字符串/undefined)。如果该变量为空,URL路径会变成/company//question,后端无法获取到合法的ID,从而报错。
  • HttpHeaders设置问题:Angular的HttpHeaders是不可变对象,append操作不会修改原对象,需要重新赋值。原代码中headers.append(...)后未更新变量,导致实际请求可能没有携带正确的请求头;另外multipart/form-data的Content-Type不需要手动设置,Angular会自动根据FormData生成正确的boundary,建议修正为:
    let headers = new HttpHeaders();
    headers = headers.append('Authorization', `Bearer ${userObject.token}`);
    headers = headers.append('Accept', 'application/json');
    
  • FormData中null值的处理:convertJsonToFormData函数会将null值直接append到FormData,部分后端框架可能无法正确解析这类值,导致字段被忽略。如果后端需要相关字段存在,可将null值转换为空字符串后再append。

内容的提问来源于stack exchange,提问作者SANYAM CHAURASIA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:53:23