NetworkError: Failed to execute 'send' on 'XMLHttpRequest': Failed to load xxxx錯誤解決方法

Caitingwei發表於2019-07-18

在開發專案的過程中,和後端對接,我們使用是一個成熟的整合很全面的架構JHipster。後端為java spring-boot 前端ts+react,需求是有一個需要在頁面裡巢狀iframe的需求。然後在iframe中發起$.ajax請求前端出現了錯誤如下:

"NetworkError: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'http://192.168.31.149:8081/api/concepts/3253'

 

前端程式碼:

$.ajax({
  url: `${RED.API.schema.URI()}/${conceptIds}`,
  method: "GET",
  async: false,
  crossDomain: true,
  headers: {
  'Access-Control-Allow-Origin': '*',
  accept: 'application/json',
  Authorization: `Bearer ${window.parent.localStorage
    .getItem("jhi-authenticationToken")
    .replace(/\"/g, "")}`,
  },
  success: data => {
    console.log(data)
  },
  error: err => {
    console.error(err)
  },
});

可以看到,只要$.ajax請求開啟關閉async開啟同步模式則就會無法請求資料。

解決方法:

經過查閱,網上的一些資訊。發現大部分解決方案都是吧async改為true就可以了。但我的專案運用裡必須使用同步來渲染資料。所以沒法改成非同步使用。

最後使用docker跑兩個容器分別模擬線上和本地的環境。發現請求的請求頭裡有著如下差異:

經過本地除錯,找到靜態檔案代理模式和本地開發模式的請求響應差異如下: 
【線上的Response Headers】 
Accept-Ranges: bytes 
Cache-Control: no-store 
Connection: keep-alive 
Content-Encoding: gzip 
Content-Language: en- 
Content-Length: 2213 
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: 
Content-Type: text/html;charset=utf-8 
Date: Thu, 18 Jul 2019 06:28:37 GMT 
Feature-Policy: geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none' 
Last-Modified: Thu, 18 Jul 2019 02:03:28 GMT 
Referrer-Policy: strict-origin-when-cross-origin 
Server: nginx/1.17.0 
X-Content-Type-Options: nosniff 
X-Frame-Options: DENY 
X-XSS-Protection: 1; mode=block 


【本地的Response Headers】 
accept-ranges: bytes 
Connection: keep-alive 
Content-Type: text/html; charset=UTF-8 
Date: Thu, 18 Jul 2019 06:40:59 GMT 
etag: W/"16de-hwm87recU2tkzw2pAE/RFVGX6+0" 
Server: nginx/1.17.0 
Transfer-Encoding: chunked 
x-powered-by: Express 

【對比差異】 
線上的多了一下設定: 
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: 
Feature-Policy: geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none' 
Referrer-Policy: strict-origin-when-cross-origin 
X-Content-Type-Options: nosniff 
X-Frame-Options: DENY 
X-XSS-Protection: 1; mode=block

結果是該框架的後端配置了一種叫Content-Security-Policy的xss安全機制,攔截的不安全的請求。隨後在java專案裡config/SecurityConfiguration.java 註釋去掉該響應頭的注入即解決問題。

// SecurityConfiguration.java

@Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .csrf()
            .disable()
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(problemSupport)
            .accessDeniedHandler(problemSupport)
        .and()
            // .headers()
            // .contentSecurityPolicy("default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:")
        // .and()
            // .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
        // .and()
            // .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
        // .and()
            // .frameOptions()
            // .sameOrigin()
        // .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
            .authorizeRequests()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/account/reset-password/init").permitAll()
            .antMatchers("/api/account/reset-password/finish").permitAll()
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/info").permitAll()
            .antMatchers("/management/prometheus").permitAll()
            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
        .and()
            .httpBasic()
        .and()
            .apply(securityConfigurerAdapter());
        // @formatter:on
    }

 

相關文章