Description
I'm encountering a CORS (Cross-Origin Resource Sharing) issue specifically when performing file upload and download operations in my angular-springboot3 application. The CORS problem occurs only with these file-related requests, while other API requests work fine.
Problem
When attempting to upload or download files, I receive the following error message in the browser console:
Acess to XMLHttpRequest at 'http://localhost:8081/api/v1/download-excel' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Additional Information:
@CrossOrigin
annotation in the backend controller for the file upload/download endpoints.withCredentials: true
option in the frontend http.post() method, but it did not resolve the CORS issue.Code snippets
Front End :
uploadExcelFile(file: File): Observable<any> {
return this.http.post(this.API_URL+'upload-excel', file);
}
downloadExcelFile(toDownload: any[]): Observable<HttpResponse<Blob>> {
var idList: number[] = []
toDownload.forEach((value)=> idList.push(value.id))
const headers = new HttpHeaders({
'Content-Type': 'application/octet-stream',
});
const params = new HttpParams().set('ids', idList.join(','));
return this.http.post<Blob>(this.API_URL+'download-excel',params, {
headers: headers,
observe: 'response',
responseType: 'blob' as 'json'
}).pipe(
catchError((error: any) => {
console.error('Error occurred during file download:', error);
throw error;
})
);
}
Back end:
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(path = "/upload-excel", method = RequestMethod.POST)
public ResponseEntity<?> uploadExcelFile(@RequestParam("file") MultipartFile file) {
ExcelUploader helper = new ExcelUploader();
List<Entity> toAdd = helper.uploadFromExcel(file);
navireRepository.saveAll(toAdd);
return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
}
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(path = "/download-excel", method = RequestMethod.GET)
public ResponseEntity<byte[]> downloadExcelFile(@RequestBody List<Navire> toDownload) throws IOException {
ExcelDownloader helper = new ExcelDownloader();
List<Navire> toDownload = new ArrayList<>();
for (Long id : ids) {
toDownload.add(repository.getReferenceById(id));
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.set("Access-Control-Allow-Origin", "*");
headers.setContentDispositionFormData("attachment", "entity.xlsx");
byte[] bytes = helper.downloadToExcel(toDownload);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
hers my security configuration too
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
private final LogoutHandler logoutHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.cors()
.disable()
.authorizeHttpRequests()
.requestMatchers("/api/v1/**", "/swagger-ui/**", "/v3/api-docs/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.logout()
.logoutUrl("/api/v1/auth/logout")
.addLogoutHandler(logoutHandler)
.logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext())
;
return http.build();
}
}
I would greatly appreciate any insights or suggestions on how to resolve this CORS issue specifically related to file upload and download feature with Spring boot 3. Thank you in advance for your help!
Solution It all went smoothly when I added a global cors configuration like so
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(0);
return bean;
}