如何从Angular 5客户端向Spring Boot后端服务传输文件?
看起来你在文件上传的跨域请求上踩了两个关键的坑,一个在前端请求格式,一个在后端CORS配置的细节上。咱们一步步来修复:
1. 先修正Angular服务的请求错误
你现在的代码里把FormData用JSON.stringify()包裹了,这完全破坏了multipart请求的格式——文件上传必须用原生的FormData对象传递,不能转成JSON。修改你的服务代码:
@Injectable() export class UploadFileService { constructor(private httpClient: HttpClient, private globals: Globals) { } pushFileToStorage(file: File) { const formData = new FormData(); formData.append('file', file); const req = this.httpClient.post( `http://localhost:${this.globals.tomcatPort}/utils/saveFromFile`, formData // 直接传FormData,不要转JSON ); req.subscribe( (data) => console.log('上传成功:', data), (err: HttpErrorResponse) => { if (err.error instanceof Error) { console.log('客户端错误:', err.error.message); } else { console.log('后端错误:', err.status, err.error); } } ); } }
另外别手动加Headers,HttpClient会自动为FormData请求设置正确的multipart/form-data头(包括自动生成的boundary分隔符),手动设置反而容易出问题。
2. 修复Spring Boot的CORS与Multipart配置
你的@CrossOrigin注解在处理multipart请求的OPTIONS预检时可能失效了,尤其是当你配置了MultipartFilter的情况下,过滤器顺序会导致CORS头没被正确添加。推荐改用全局CORS配置,更可靠:
新增全局CORS配置类
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("http://localhost:4200"); config.addAllowedMethod("*"); // 允许所有请求方法 config.addAllowedHeader("*"); // 允许所有请求头 config.setAllowCredentials(true); config.setMaxAge(3600L); // 预检请求缓存1小时 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
然后把Controller上的@CrossOrigin注解删掉,全局配置已经覆盖了这部分功能。
修正MultipartFilter的拼写错误
你代码里的multipartResolverBeanName有隐藏的特殊字符,导致Spring找不到对应的Resolver,修正后:
@Bean @Order(0) public MultipartFilter multipartFilter() { MultipartFilter multipartFilter = new MultipartFilter(); // 修正拼写错误,去掉隐藏字符 multipartFilter.setMultipartResolverBeanName("multipartResolver"); return multipartFilter; }
改用Spring原生的MultipartResolver(可选但推荐)
Spring Boot 2.x+推荐使用基于Servlet 3.0的StandardServletMultipartResolver,比Apache Commons的实现更轻量,替换你原来的CommonsMultipartResolver:
@Bean public StandardServletMultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); }
同时在application.properties里添加文件上传限制:
spring.servlet.multipart.max-file-size=3MB spring.servlet.multipart.max-request-size=3MB
问题根源总结
- 前端错误地将FormData转成JSON,导致请求格式完全不符合multipart要求,触发了异常的预检请求;
- 后端
@CrossOrigin在处理multipart的OPTIONS预检时,因为过滤器顺序问题(MultipartFilter先执行),没有正确添加CORS头,返回403; - MultipartFilter的bean名称拼写错误,导致文件解析逻辑失效。
按上面的步骤修复后,应该就能正常完成文件上传了。
内容的提问来源于stack exchange,提问作者Matexon

