簡體   English   中英

Spring Boot + Angular - MultipartException:當前請求不是多部分請求

[英]Spring Boot + Angular - MultipartException: Current request is not a multipart request

我在將 Angular 9 與 Spring Boot 一起用於一個簡單的應用程序時遇到問題,該應用程序在同一請求中上傳文件以及來自 UI 的數據。 在我使用基本身份驗證實現安全之前,一切正常。 現在,在我登錄並想要上傳數據后,我收到以下錯誤:

org.springframework.web.multipart.MultipartException: Current request is not a multipart request

將標頭設置為Content-Type: 'multipart/form-data'和使用 MultipartFile 的 Spring Controller。 奇怪的是 GET 請求運行良好,除了它的內容類型是application/json 如果我禁用了 http-interceptor,則錯誤變為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 我還嘗試了所有處理 Angular 和 Spring 相關的 CORS 的解決方法,但沒有成功。

用於上傳文件的 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();
  }

角度認證服務:

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);
  }

角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);
  }

彈簧安全配置:

@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

從源“ http://localhost:4200 ”訪問“ http://localhost:8080/pacient ”的 XMLHttpRequest 已被 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
  }
}

並將其添加到 package.json,以"start": "ng serve --proxy-config proxy.conf.json"並在我的 Spring Security 配置類中添加 CORS 配置

@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;
    }

但仍然沒有運氣...

我自己也遇到了這個問題,這對我來說是一個非常愚蠢的錯誤,但我想我應該分享一下,以防有人犯同樣的錯誤。 我剛剛將文件移到了我的虛擬機上,而我的用戶帳戶無權訪問該文件……一旦我更改了文件的權限,它就按預期工作了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM