У меня проблема с использованием Angular 9 с Spring Boot для простого приложения, которое загружает файлы вместе с данными из пользовательского интерфейса в том же запросе. Пока я не реализовал безопасность с аутентификацией basi c, все работало просто отлично. Теперь, после того, как я вошел в систему и хочу загрузить данные, я получаю следующую ошибку:
org.springframework.web.multipart.MultipartException: Current request
is not a multipart request
с заголовками, установленными на Content-Type: 'multipart/form-data'
и Spring Controller, использующий MultipartFile. Странно то, что запрос GET работает хорошо, за исключением того, что его тип контента application/json
. Если я отключаю http-перехватчик, ошибка становится Access to XMLHttpRequest at 'http://localhost:8080/pacients' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
. Я также пробовал каждый обходной путь для обработки CORS, как Angular, так и Spring, безуспешно.
Angular компонент для загрузки файла:
pacient: Pacient;
pacientForm: FormGroup = new PacientCreateFormBuilder().build();
submitPromise: Promise<Pacient>;
onSubmit() {
if(this.pacientForm.valid) {
const formData: FormData = new FormData();
formData.append('pacientFile', <File>this.pacientForm.value.pacientFile);
formData.append('newPacient', new Blob([JSON.stringify(this.pacientForm.value)], {type: "application/json"}));
this.submitPromise = this.pacientCreateService.save(formData);
} else {
ValidationUtils.markFormAsDirty(this.pacientForm);
}
}
Angular сервис для загрузки:
public save(formData: FormData) {
var headers = new HttpHeaders(
{
'Content-Type': 'multipart/form-data',
'Authorization': `Basic ${window.btoa(this.authService.username + ":" + this.authService.password)}`
}
);
return this.httpClient.post<Pacient>("http://localhost:8080/pacient", formData, {headers: headers})
.toPromise();
}
Angular сервис аутентификации:
authenticate(username: String, password: String) {
return this.http.get(`http://localhost:8080/auth`, {
headers: { authorization: this.createBasicAuthToken(username, password) }}).pipe(map((res) => {
this.username = username;
this.password = password;
this.registerInSession(username, password);
}));
}
createBasicAuthToken(username: String, password: String) {
return 'Basic ' + window.btoa(username + ":" + password);
}
registerInSession(username, password) {
sessionStorage.setItem(this.SESSION_KEY, username);
}
Angular http-перехватчик:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService.isUserLoggedin() && req.url.indexOf('basicauth') === -1) {
const request = req.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Basic ${window.btoa(this.authService.username + ":" + this.authService.password)}`
})
});
return next.handle(request);
}
return next.handle(req);
}
Spring Security config:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = new StandardPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER")
.and()
.withUser("admin")
.password("admin")
.roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().
disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
Пружинный контроллер:
@PostMapping("/pacient")
public Pacient create(@RequestPart("pacientFile") MultipartFile pacientFile, @RequestPart("newPacient") PacientDTO pacientDTO)
РЕДАКТИРОВАТЬ: Если я использую @PostMapping(value = "/pacient", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
в контроллере, ошибка меняется и появляется только на консоли браузера и sais
Доступ к XMLHttpRequest в 'http://localhost: 8080 / pacient ' from origin 'http://localhost: 4200 ' заблокирован политикой CORS : На запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin».
Чтобы обойти его, я обновил контроллер с помощью @CrossOrigin(origins = {"http://localhost:4200"})
, добавил следующие поля в заголовки из сервиса
'Access-Control-Allow-Headers': `Content-Type`,
'Access-Control-Allow-Methods': `POST`,
'Access-Control-Allow-Origin': `*`
, а также создали файл proxy.conf. json с
{
"/": {
"target": "http://localhost:8080",
"secure": false
}
}
и добавили его в пакет. * 10 66 *, для начала "start": "ng serve --proxy-config proxy.conf.json"
и добавили конфигурацию CORS в мой класс конфигурации Spring Security
@Bean
CorsConfigurationSource corsConfigurationSource()
{
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
, но все равно не повезло ...