#yyds干货盘点#跨域问题之Spring的跨域的方案

Posted 周杰伦本人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点#跨域问题之Spring的跨域的方案相关的知识,希望对你有一定的参考价值。

Spring的跨域的方案

@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();
   
  1. @CrossOrigin 注解在AbstractHandlerMethodMapping的内部类MappingRegistry的register方法中完成解析,@CrossOrigin注解中的内容会被解析成一个配置对象CorsConfiguration
  2. 将@CrossOrigin所标记的请求方法对象HandlerMethod和CorsConfiguration一一对应存入corsLookup的map集合中
  3. 当请求到达DispatcherServlet的doDispatch方法之后,调用AbstractHandlerMapping的getHandler方法获取执行链HandlerExecutionChain时,会从map中获取CorsConfiguration对象
  4. 根据获取到的CorsConfiguration对象构建一个CorsInterceptor拦截器
  5. 在CorsInterceptor拦截器中触发对CorsProcessor的processRequest方法调用,跨域请求的校验工作将在该方法中完成。

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方法调用,最终在该方法中完成跨域请求的校验工作

  1. registry.addMapping("/**")方法中配置了一个CorsRegistration对象,该对象中包含了一个路径拦截规则,同时CorsRegistration还包含了一个CorsConfiguration配置对象,该对象用来保存这里跨域相关的配置。
  2. 在WebMvcConfigurationSupport的requestMappingHandlerMapping方法中触发了addCorsMappings方法执行,将获取到的CorsRegistration对象重新组装成一个UrlBasedCorsConfigurationSource对象,该对象保存了拦截规则和CorsConfiguration对象的映射关系。
  3. 将新建的UrlBasedCorsConfigurationSource对象赋值给AbstractHandlerMapping的corsConfigurationSource属性
  4. 当请求到达时的处理方法和@CrossOrigin注解处理流程一样,在AbstractHandlerMapping的getHandler方法处理,从corsConfigurationSource中获取CorsConfiguration配置对象,而@CrossOrigin从map中获取CorsConfiguration对象。如果两处都可以获取到CorsConfiguration对象,则获取到的对象属性值进行合并。
  5. 根据获取到的CorsConfiguration对象构造CorsInterceptor拦截器
  6. 在CorsInterceptor拦截器中触发对CorsProcessor的processRequest方法调用,跨域请求的校验工作将在该方法中完成。

这里的跨域校验是通过DispatcherServlet中的方法触发的,DispatcherServlet在Filter之后执行

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;
    
  1. 手动创建CorsConfiguration对象
  2. 创建UrlBasedCorsConfigurationSource对象,将过滤器的拦截规则和CorsConfiguration对象之间的映射关系由UrlBasedCorsConfigurationSource中的corsConfiguration变量保存起来。
  3. 最后创建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);
    

触发对CorsProcessor的processRequest方法调用,跨域请求的校验工作将在该方法中完成

以上是关于#yyds干货盘点#跨域问题之Spring的跨域的方案的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#java内存模型之final域的内存语义

Spring MVC 的跨域解决方案

Spring MVC的跨域访问

Spring MVC的跨域访问

解决Vue http中的跨域问题

Spring Boot 中处理跨域