欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring @CrossOrigin 注解原理實現

 更新時間:2020年07月08日 11:54:46   作者:暗中觀察  
這篇文章主要介紹了Spring @CrossOrigin 注解原理實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

現實開發(fā)中,我們難免遇到跨域問題,以前筆者只知道jsonp這種解決方式,后面聽說spring只要加入@CrossOrigin即可解決跨域問題。本著好奇的心里,筆者看了下@CrossOrigin 作用原理,寫下這篇博客。

先說原理:其實很簡單,就是利用spring的攔截器實現往response里添加 Access-Control-Allow-Origin等響應頭信息,我們可以看下spring是怎么做的

注:這里使用的spring版本為5.0.6

我們可以先往RequestMappingHandlerMapping 的initCorsConfiguration方法打一個斷點,發(fā)現方法調用情況如下

如果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);
 }

再看下getCorsHandlerExecutionChain 是如何獲取一個handler

 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 {
      //只是給執(zhí)行器鏈添加了一個攔截器
  chain.addInterceptor(new CorsInterceptor(config));
 }
 return chain;
 }

也就是在調用目標方法前會先調用CorsInterceptor#preHandle,我們觀察得到其也是調用了corsProcessor.processRequest方法,我們往這里打個斷點

processRequest方法的主要邏輯如下

 public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
  HttpServletResponse response) throws IOException {
    //....
    //調用了自身的handleInternal方法
 return handleInternal(serverRequest, serverResponse, config, preFlightRequest);
 }


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;
 }

 HttpMethod requestMethod = getMethodToUse(request, preFlightRequest);
 List<HttpMethod> allowMethods = checkMethods(config, requestMethod);
 if (allowMethods == null) {
  logger.debug("Rejecting CORS request because '" + requestMethod + "' request method is not allowed");
  rejectRequest(response);
  return false;
 }

 List<String> requestHeaders = getHeadersToUse(request, preFlightRequest);
 List<String> allowHeaders = checkHeaders(config, requestHeaders);
 if (preFlightRequest && allowHeaders == null) {
  logger.debug("Rejecting CORS request because '" + requestHeaders + "' request headers are not allowed");
  rejectRequest(response);
  return false;
 }
    //設置響應頭
 responseHeaders.setAccessControlAllowOrigin(allowOrigin);

 if (preFlightRequest) {
  responseHeaders.setAccessControlAllowMethods(allowMethods);
 }

 if (preFlightRequest && !allowHeaders.isEmpty()) {
  responseHeaders.setAccessControlAllowHeaders(allowHeaders);
 }

 if (!CollectionUtils.isEmpty(config.getExposedHeaders())) {
  responseHeaders.setAccessControlExposeHeaders(config.getExposedHeaders());
 }

 if (Boolean.TRUE.equals(config.getAllowCredentials())) {
  responseHeaders.setAccessControlAllowCredentials(true);
 }

 if (preFlightRequest && config.getMaxAge() != null) {
  responseHeaders.setAccessControlMaxAge(config.getMaxAge());
 }
    //刷新
 response.flush();
 return true;
 }

至此@CrossOrigin的使命就完成了,說白了就是用攔截器給response添加響應頭信息而已

到此這篇關于Spring @CrossOrigin 注解原理實現的文章就介紹到這了,更多相關Spring @CrossOrigin 注解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現順序棧的示例代碼

    Java實現順序棧的示例代碼

    線性表和棧都是我們常用的數據結構,??梢钥闯梢环N特殊狀態(tài)的線性表。線性表分為順序表和鏈表,使用線性表中的順序表來實現棧時這種棧被稱為順序棧。這篇文章總結了如何使用順序表實現棧,需要的可以參考一下
    2022-11-11
  • Java volatile如何實現禁止指令重排

    Java volatile如何實現禁止指令重排

    這篇文章主要介紹了Java volatile如何實現禁止指令重排,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Dubbo?LoadBalance基于權重的隨機負載均衡算法提高服務性能

    Dubbo?LoadBalance基于權重的隨機負載均衡算法提高服務性能

    這篇文章主要為大家介紹了Dubbo?LoadBalance基于權重的隨機負載均衡算法提高服務性能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2023-10-10
  • Java基礎之不簡單的數組

    Java基礎之不簡單的數組

    數組(Array)是有序的元素序列。 若將有限個類型相同的變量的集合命名,那么這個名稱為數組名。組成數組的各個變量稱為數組的分量,也稱為數組的元素,有時也稱為下標變量
    2021-09-09
  • 通過Session案例分析一次性驗證碼登錄

    通過Session案例分析一次性驗證碼登錄

    這篇文章主要介紹了通過Session案例分析一次性驗證碼登錄,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • fasterxml jackson反序列化時對于非靜態(tài)內部類報錯問題及解決

    fasterxml jackson反序列化時對于非靜態(tài)內部類報錯問題及解決

    這篇文章主要介紹了fasterxml jackson反序列化時對于非靜態(tài)內部類報錯問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java五子棋單機版源碼分享

    Java五子棋單機版源碼分享

    這篇文章主要為大家分享了Java五子棋單機版源碼,JavaGUI編寫單機版五子棋,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 一文搞懂Java頂層類之Object類的使用

    一文搞懂Java頂層類之Object類的使用

    java.lang.Object類是Java語言中的根類,即所有類的父類。它中描述的所有方法子類都可以使用。本文主要介紹了Object類中toString和equals方法的使用,感興趣的小伙伴可以了解一下
    2022-11-11
  • java內存模型jvm虛擬機簡要分析

    java內存模型jvm虛擬機簡要分析

    Java 內存模型的主要目的是定義程序中各種變量的訪問規(guī)則, 關注在虛擬機中把變量值存儲到內存和從內存中取出變量值這樣的底層細節(jié)
    2021-09-09
  • 淺談java8中map的新方法--replace

    淺談java8中map的新方法--replace

    下面小編就為大家?guī)硪黄獪\談java8中map的新方法--replace。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10

最新評論