現實開發中,我們難免遇到跨域問題,以前筆者只知道jsonp這種解決方式,后面聽說spring只要加入@CrossOrigin即可解決跨域問題。本着好奇的心里,筆者看了下@CrossOrigin 作用原理,寫下這篇博客。
先說原理:其實很簡單,就是利用spring的攔截器實現往response里添加 Access-Control-Allow-Origin等響應頭信息,我們可以看下spring是怎么做的
注:這里使用的spring版本為5.0.6
我們可以先往RequestMappingHandlerMapping 的initCorsConfiguration方法打一個斷點,發現方法調用情況如下
如果controller在類上標了@CrossOrigin或在方法上標了@CrossOrigin注解,則spring 在記錄mapper映射時會記錄對應跨域請求映射,代碼如下
RequestMappingHandlerMapping protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) { HandlerMethod handlerMethod = createHandlerMethod(handler, method); Class<?> beanType = handlerMethod.getBeanType(); //獲取handler上的CrossOrigin 注解 CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class); //獲取handler 方法上的CrossOrigin 注解 CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class); if (typeAnnotation == null && methodAnnotation == null) { //如果類上和方法都沒標CrossOrigin 注解,則返回一個null return null; } //構建一個CorsConfiguration 並返回 CorsConfiguration config = new CorsConfiguration(); updateCorsConfig(config, typeAnnotation); updateCorsConfig(config, methodAnnotation); if (CollectionUtils.isEmpty(config.getAllowedMethods())) { for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) { config.addAllowedMethod(allowedMethod.name()); } } return config.applyPermitDefaultValues(); }
將結果返回到了AbstractHandlerMethodMapping#register,主要代碼如下
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) { //會保存handlerMethod處理跨域請求的配置 this.corsLookup.put(handlerMethod, corsConfig); }
當一個跨域請求過來時,spring在獲取handler時會判斷這個請求是否是一個跨域請求,如果是,則會返回一個可以處理跨域的handler
AbstractHandlerMapping#getHandler
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//如果是一個跨域請求 if (CorsUtils.isCorsRequest(request)) { //拿到跨域的全局配置 CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request); //拿到hander的跨域配置 CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); //處理跨域(即往響應頭添加Access-Control-Allow-Origin信息等),並返回對應的handler對象 executionChain = getCorsHandlerExecutionChain(request, executionChain, config); }
我們可以看下如何判定一個請求是一個跨域請求,
public static boolean isCorsRequest(HttpServletRequest request) { //判定請求頭是否有Origin 屬性即可 return (request.getHeader(HttpHeaders.ORIGIN) != null); }
轉自:https://www.liangzl.com/get-article-detail-114619.html