首頁 > 軟體

Spring的跨域的幾個方案

2022-02-18 16:00:35

1.@CrossOrigin

@CrossOrigin可以新增到方法上,也可以新增到Controller

AbstractHandlerMethodMapping的內部類MappingRegistry的register:

public void register(T mapping, Object handler, Method method) {
   // Assert that the handler method is not a suspending one.
   if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
      Class<?>[] parameterTypes = method.getParameterTypes();
      if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
         throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
      }
   }
   this.readWriteLock.writeLock().lock();
   try {
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      validateMethodMapping(handlerMethod, mapping);
      this.mappingLookup.put(mapping, handlerMethod);

      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
         this.urlLookup.add(url, mapping);
      }

      String name = null;
      if (getNamingStrategy() != null) {
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);
      }

      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
      if (corsConfig != null) {
         this.corsLookup.put(handlerMethod, corsConfig);
      }

      this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
   }
   finally {
      this.readWriteLock.writeLock().unlock();
   }
}
  • @CrossOrigin 註解在AbstractHandlerMethodMapping的內部類MappingRegistry的register方法中完成解析,@CrossOrigin註解中的內容會被解析成一個設定物件CorsConfiguration
  • @CrossOrigin所標記的請求方法物件HandlerMethodCorsConfiguration一一對應存入corsLookup的map集合中
  • 當請求到達DispatcherServlet的doDispatch方法之後,呼叫AbstractHandlerMapping的getHandler方法獲取執行鏈HandlerExecutionChain時,會從map中獲取CorsConfiguration物件
  • 根據獲取到的CorsConfiguration物件構建一個CorsInterceptor攔截器
  • CorsInterceptor攔截器中觸發對CorsProcessor的processRequest方法呼叫,跨域請求的校驗工作將在該方法中完成。

2.addCorsMappings

@CrossOrigin是新增在不同的Controller中 全域性設定

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("*")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowCredentials(false)
                .exposedHeaders("")
                .maxAge(3600);
    }
}

全域性設定和@CrossOrigin註解相同,都是在CorsInterceptor攔截器中觸發對CorsProcessor的processRequest方法呼叫,最終在該方法中完成跨域請求的校驗工作

  • registry.addMapping(“/**”)方法中設定了一個CorsRegistration物件,該物件中包含了一個路徑攔截規則,同時CorsRegistration還包含了一個CorsConfiguration設定物件,該物件用來儲存這裡跨域相關的設定。
  • WebMvcConfigurationSupportrequestMappingHandlerMapping方法中觸發了addCorsMappings方法執行,將獲取到的CorsRegistration物件重新組裝成一個UrlBasedCorsConfigurationSource物件,該物件儲存了攔截規則和CorsConfiguration物件的對映關係。
  • 將新建的UrlBasedCorsConfigurationSource物件賦值給AbstractHandlerMapping的corsConfigurationSource屬性
  • 當請求到達時的處理方法和@CrossOrigin註解處理流程一樣,在AbstractHandlerMapping的getHandler方法處理,從corsConfigurationSource中獲取CorsConfiguration設定物件,而@CrossOrigin從map中獲取CorsConfiguration物件。如果兩處都可以獲取到CorsConfiguration物件,則獲取到的物件屬性值進行合併。
  • 根據獲取到的CorsConfiguration物件構造CorsInterceptor攔截器
  • CorsInterceptor攔截器中觸發對CorsProcessor的processRequest方法呼叫,跨域請求的校驗工作將在該方法中完成。

這裡的跨域校驗是通過DispatcherServlet中的方法觸發的,DispatcherServlet在Filter之後執行

3.CorsFIlter

@Configuration
public class WebMvcConfig {
    @Bean
    FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8081"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        registrationBean.setFilter(new CorsFilter(source));
        registrationBean.setOrder(-1);
        return registrationBean;
    }
}
  • 手動建立CorsConfiguration物件
  • 建立UrlBasedCorsConfigurationSource物件,將過濾器的攔截規則和CorsConfiguration物件之間的對映關係由UrlBasedCorsConfigurationSource中的corsConfiguration變數儲存起來。
  • 最後建立CorsFilter 設定優先順序

CorsFilter的doFilterInternal方法:

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
    boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
    if (isValid && !CorsUtils.isPreFlightRequest(request)) {
        filterChain.doFilter(request, response);
    }
}

觸發對CorsProcessorprocessRequest方法呼叫,跨域請求的校驗工作將在該方法中完成

到此這篇關於Spring的跨域的幾個方案的文章就介紹到這了,更多相關Spring的跨域方案內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com