Angular 13向Java后端提交FormData请求报400/415错误
Angular 13 发送FormData到Java后端请求异常解决方案
问题复现代码
前端 Service 代码(applicationservice.ts)
aggiungiApplicazione(appForm: FormData): Observable<Applicazione> { return this.http.post<Applicazione>(`http://localhost:8080/Gestionale/api/applicazione/aggiunta`, appForm, {headers: { "Content-Type": "application/json" }}); }
前端组件代码(component.ts)
const appFormData = new FormData(); Object.keys(this.appForm).map((key) => { appFormData.append(key, this.appForm[key].value); }) _aggiungiApplicazione(appData: FormData) { this.applicazioneService.aggiungiApplicazione(appData).subscribe((app: Applicazione) => { console.log(app); timer(2000).toPromise().then(() => { this.display = false; this._getApplicazioni(); }) }); }
后端接口代码
@POST @Path("aggiunta") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Applicazione add(Applicazione a) { JpaDaoFactory.getDaoFactory().save(a); return a; }
报错表现
- 手动指定
Content-Type: application/json请求头时,返回400 Bad Request:
ERROR
Type Status Report
Message Bad Request
Description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
- 移除手动配置的Content-Type请求头后,返回415 Unsupported Media Type错误。
故障原因
前后端请求数据格式配置完全不匹配:
- 手动给FormData请求设置
application/json头时,请求体实际是多段分隔的二进制FormData格式,后端按JSON规则解析必然失败,触发400错误。 - 删掉手动设置的请求头后,浏览器会自动给FormData请求加上
multipart/form-data头(附带自动生成的boundary分隔符,这个参数不能手动设置),但后端接口通过@Consumes(MediaType.APPLICATION_JSON)配置了只接收JSON格式请求,识别不了form-data类型,直接返回415错误。
修复方案
根据业务是否有文件上传需求二选一:
方案1:无文件上传场景(改动最小)
不需要构造FormData,直接发送JSON格式数据,后端代码完全不用改:
- 修改组件逻辑,删掉FormData构造代码,直接传表单值:
_aggiungiApplicazione() { const appData = this.appForm.value; this.applicazioneService.aggiungiApplicazione(appData).subscribe((app: Applicazione) => { console.log(app); timer(2000).toPromise().then(() => { this.display = false; this._getApplicazioni(); }) }); }
- 修改Service层代码,删掉手动设置的Content-Type头,Angular会自动给JSON请求配置正确的请求头:
aggiungiApplicazione(appForm: Partial<Applicazione>): Observable<Applicazione> { return this.http.post<Applicazione>(`http://localhost:8080/Gestionale/api/applicazione/aggiunta`, appForm); }
方案2:包含文件上传、必须用FormData的场景
需要同时修改前后端配置,匹配multipart/form-data格式:
- 前端Service层删掉手动设置的Content-Type头,绝对不能手动设置这个头,否则会丢失浏览器自动生成的boundary参数,直接导致后端解析失败:
aggiungiApplicazione(appForm: FormData): Observable<Applicazione> { return this.http.post<Applicazione>(`http://localhost:8080/Gestionale/api/applicazione/aggiunta`, appForm); }
- 修改后端接口配置,将
@Consumes的值改为MediaType.MULTIPART_FORM_DATA,同时调整参数接收方式。如果是Jersey框架,需要先引入multipart解析依赖,再通过@FormParam接收普通字段、@FormDataParam接收文件字段;如果是Spring Boot框架,直接用@RequestPart或@ModelAttribute注解绑定参数到实体类即可。
示例(Jersey框架):
@POST @Path("aggiunta") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) public Applicazione add( @FormParam("nome") String nome, @FormParam("descrizione") String descrizione ) { Applicazione a = new Applicazione(); a.setNome(nome); a.setDescrizione(descrizione); JpaDaoFactory.getDaoFactory().save(a); return a; }
内容的提问来源于stack exchange,提问作者Antonio Nusco
相关产品推荐
相关产品推荐

