在我的 Spring Web 应用程序中,我有一个需要 excel 文件的方法。它作为请求的参数发送到我的 RESful API。媒体类型设置为 MediaType.MULTIPART_FORM_DATA_VALUE。
@RestController
@RequestMapping("/personal-info")
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN')")
public class PersonalInfoController {
private final PersonalInfoService personalInfoService;
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadPersonalInfo(@RequestParam("file") MultipartFile file) {
this.personalInfoService.seedPersonalInfo(file);
return new ResponseEntity<>("File uploaded and database seeded successfully", HttpStatus.OK);
}
}
发送请求的 React 客户端如下所示:
export const uploadPersonalInfo = async (file) => {
const formData = new FormData();
formData.append('file', file);
await fetch(`${API_BASE_URL}/personal-info/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${authenticationService.getToken()}`
}
});
};
我没有在标题中显式设置内容类型,因为我让浏览器自动执行此操作。日志如下所示:
2024-09-01T10:40:03.906+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing OPTIONS /api/personal-info/upload
2024-09-01T10:40:03.911+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing POST /api/personal-info/upload
2024-09-01T10:40:03.917+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] org.hibernate.SQL :
select
u1_0.id,
u1_0.email,
u1_0.has_voted,
u1_0.password,
u1_0.personal_info_id,
u1_0.role
from
users u1_0
where
u1_0.email=?
2024-09-01T10:40:03.919+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] org.hibernate.SQL :
select
pi1_0.id,
pi1_0.egn,
pi1_0.first_name,
pi1_0.id_number,
pi1_0.last_name,
pi1_0.middle_name,
u1_0.id,
u1_0.email,
u1_0.has_voted,
u1_0.password,
u1_0.role
from
personal_infos pi1_0
left join
users u1_0
on pi1_0.id=u1_0.personal_info_id
where
pi1_0.id=?
2024-09-01T10:40:03.925+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Secured POST /api/personal-info/upload
2024-09-01T10:40:03.926+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : POST "/api/personal-info/upload", parameters={}
2024-09-01T10:40:03.927+03:00 WARN 18504 --- [VotingSystem] [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type is not supported]
2024-09-01T10:40:03.927+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed 415 UNSUPPORTED_MEDIA_TYPE
2024-09-01T10:40:03.927+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing POST /error
2024-09-01T10:40:03.929+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-09-01T10:40:03.929+03:00 DEBUG 18504 --- [VotingSystem] [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
我尝试更改 CORS 配置,因为一开始我认为它可能存在问题。它还没有解决问题,到目前为止我正在使用这个配置:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
此外,它不可能是缺少依赖项或多部分配置问题,因为我已经正确设置了所有约束:
servlet:
multipart:
enabled: true
max-file-size: 10MB
max-request-size: 10MB
file-size-threshold: 10MB
发送文件时,请将
Content-Type
设置为multipart/form-data
。
更新了 React 客户端:
export const uploadPersonalInfo = async (file) => {
const formData = new FormData();
formData.append('file', file);
await fetch(`${API_BASE_URL}/personal-info/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${authenticationService.getToken()}`,
'Content-Type': `multipart/form-data`
}
});
};