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

学向勤中得,萤窗万卷书。这篇文章主要讲述#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方法调用,跨域请求的校验工作将在该方法中完成。
【#yyds干货盘点#跨域问题之Spring的跨域的方案】这里的跨域校验是通过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方法调用,跨域请求的校验工作将在该方法中完成

    推荐阅读