javascript
Spring @CrossOrigin 通配符 解决跨域问题
@CrossOrigin 通配符 解決跨域問題
痛點:
對很多api接口需要 開放H5 Ajax跨域請求支持 由于環境多套域名不同,而CrossOrigin 原生只支持* 或者具體域名的跨域支持 所以想讓CrossOrigin 支持下通配 *.abc.com 支持所有origin 為 abc.com域(包括各種子域名)名來的Ajax 請求支持跨域.
解決思路:
支持通配
@CrossOrigin(origins = {"*.abc.com"}) 通配 主域+任意子域 www.abc.com order.api.abc.com dev.order.abc.com 等
@CrossOrigin(origins = {"*.order.abc.com"}) 通配order子域 子域名 dev.order.abc.com test.order.abc.com uat.order.abc.com 等
Spring 默認支持cors 拓展下 Spring 對跨域的處理類
解決方案:
獲取 RequestMappingHandlerMapping 設置自定義 MyCorsProcessor 代替DefaultCorsProcessor
/*** 給requestMappingHandlerMapping 對象注入自定義 MyCorsProcessor* @author tomas* @create 2019/8/12**/ @Configuration @EnableWebMvc public class MyWebMvcConfig extends DelegatingWebMvcConfiguration {@Beanpublic RequestMappingHandlerMapping requestMappingHandlerMapping() {RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();handlerMapping.setCorsProcessor(new MyCorsProcessor());return handlerMapping;} } /*** MyCorsProcessor 描述* 自定義 如果xxx.com域下的請求允許跨域** @author tomas* @create 2019/8/12**/ public class MyCorsProcessor extends DefaultCorsProcessor {/*** Check the origin of the request against the configured allowed origins.* @param requestOrigin the origin to check* @return the origin to use for the response, or {@code null} which* means the request origin is not allowed*/@Nullablepublic String checkOrigin(CorsConfiguration config, @Nullable String requestOrigin) {if (!StringUtils.hasText(requestOrigin)) {return null;}if (ObjectUtils.isEmpty(config.getAllowedOrigins())) {return null;}if (config.getAllowedOrigins().contains(CorsConfiguration.ALL)) {if (config.getAllowCredentials() != Boolean.TRUE) {return CorsConfiguration.ALL;}else {return requestOrigin;}}AntPathMatcher pathMatcher = new AntPathMatcher("|"); for (String allowedOrigin :config.getAllowedOrigins()) {if (requestOrigin.equalsIgnoreCase(allowedOrigin)) {return requestOrigin;}//推薦方式:正則 注意(CrossOrigin(origins = {"*.abc.com"}) ) 主域會匹配主域+子域 origins = {"*.pay.abc.com"} 子域名只會匹配子域if(pathMatcher.isPattern(allowedOrigin)&&pathMatcher.match(allowedOrigin,requestOrigin)){return requestOrigin;}//不推薦方式:寫死if(allowedOrigin.contains("*.abc.com")&& requestOrigin.contains("abc.com")){return requestOrigin;}}return null;} }原理分析:
Spring mvc cors
Spring MVC 的文檔這樣說:
Spring MVC 的 HandlerMapping 實現內置支持 CORS, 在成功映射一個請求到一個 handler 之后, HandlerMapping 會檢查 CORS 配置以采取下一步動作。
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors-processing
Spring MVC 會在找到 handler 后通過添加一個攔截器來檢查 CORS 配置。
下面來看一下 Spring MVC 中的 CORS 的實現。
DispatcherServlet 調用 AbstractHandlerMapping 中的 getHandler() 方法:
對于 Ajax 請求 getCorsHandlerExecutionChain 自動加上一個 CorsInterceptor 的攔截器:
/*** Update the HandlerExecutionChain for CORS-related handling.* <p>For pre-flight requests, the default implementation replaces the selected* handler with a simple HttpRequestHandler that invokes the configured* {@link #setCorsProcessor}.* <p>For actual requests, the default implementation inserts a* HandlerInterceptor that makes CORS-related checks and adds CORS headers.* @param request the current request* @param chain the handler chain* @param config the applicable CORS configuration (possibly {@code null})* @since 4.2*/ protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,HandlerExecutionChain chain, @Nullable CorsConfiguration config) {if (CorsUtils.isPreFlightRequest(request)) {HandlerInterceptor[] interceptors = chain.getInterceptors();chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);}else {chain.addInterceptor(new CorsInterceptor(config));}return chain;}AbstractHandlerMapping中 私有class CorsInterceptor
private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {@Nullableprivate final CorsConfiguration config;public CorsInterceptor(@Nullable CorsConfiguration config) {this.config = config;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return corsProcessor.processRequest(this.config, request, response);}@Override@Nullablepublic CorsConfiguration getCorsConfiguration(HttpServletRequest request) {return this.config;}}CorsInterceptor中preHandle方法 實際處理 processRequest的是AbstractHandlerMapping.this.corsProcessor
這個corsProcessor =new DefaultCorsProcessor() 是一個默認的跨域處理類
我們的重點就是 重寫DefaultCorsProcessor的checkOrigin 方法
@Override@SuppressWarnings("resource")public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,HttpServletResponse response) throws IOException {if (!CorsUtils.isCorsRequest(request)) {return true;}......return handleInternal(serverRequest, serverResponse, config, preFlightRequest);}/*** Handle the given request.*/protected boolean handleInternal(ServerHttpRequest request, ServerHttpResponse response,CorsConfiguration config, boolean preFlightRequest) throws IOException {String requestOrigin = request.getHeaders().getOrigin();String allowOrigin = checkOrigin(config, requestOrigin);HttpHeaders responseHeaders = response.getHeaders();responseHeaders.addAll(HttpHeaders.VARY, Arrays.asList(HttpHeaders.ORIGIN,HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS));if (allowOrigin == null) {logger.debug("Rejecting CORS request because '" + requestOrigin + "' origin is not allowed");rejectRequest(response);return false;}..........response.flush();return true;}/*** Check the origin and determine the origin for the response. The default* implementation simply delegates to* {@link org.springframework.web.cors.CorsConfiguration#checkOrigin(String)}.*/// 重寫此方法 支持通配符 或者支持正則表達式 寫法見開頭解決方案@Nullableprotected String checkOrigin(CorsConfiguration config, @Nullable String requestOrigin) {return config.checkOrigin(requestOrigin);} }dispatcherServlet 中在真正 invoke handler 之前會先調用攔截器: 從而通過加的 cors 攔截器阻止請求。
doDispatch 方法:
注意問題:
除了細粒度、基于注釋的配置之外,您還可能需要定義一些全局 CORS 配置。這類似于使用篩選器,但可以聲明為 Spring MVC 并結合細粒度 @CrossOrigin 配置。默認情況下,所有 origins and GET, HEAD and POST methods 是允許的。
使整個應用程序的 CORS 簡化為:
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurer {? @Override? public void addCorsMappings(CorsRegistry registry) {? registry.addMapping("/**");? }}作為上述其他方法的替代,Spring 框架還提供了 CorsFilter。在這種情況下,不用使用@CrossOrigin或``WebMvcConfigurer#addCorsMappings(CorsRegistry),,例如,可以在 Spring Boot 應用程序中聲明如下的過濾器:
@Configurationpublic class MyConfiguration {? @Bean? public FilterRegistrationBean corsFilter() {? UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();? CorsConfiguration config = new CorsConfiguration();? config.setAllowCredentials(true);? config.addAllowedOrigin("http://domain1.com");? config.addAllowedHeader("*");? config.addAllowedMethod("*");? source.registerCorsConfiguration("/**", config);? FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));? bean.setOrder(0);? return bean;? }}感謝 @大神張林峰老師 @王昆老師 @中睿老師 給出的寶貴意見
1、官方文檔 https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
2、https://blog.csdn.net/weixin_33713503/article/details/88039675
https://www.jianshu.com/p/d05303d34222
https://www.cnblogs.com/helloz/p/10961039.html
2、https://blog.csdn.net/taiyangnimeide/article/details/78305131
3、https://blog.csdn.net/snowin1994/article/details/53035433
* * *
轉載于:https://www.cnblogs.com/wangdaijun/p/11348463.html
總結
以上是生活随笔為你收集整理的Spring @CrossOrigin 通配符 解决跨域问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: k8s nginx ingress配置T
- 下一篇: [Spring cloud 一步步实现广