最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring的@CrossOrigin注解處理請(qǐng)求源碼解析

 更新時(shí)間:2023年12月02日 10:12:18   作者:securitit  
這篇文章主要介紹了Spring的@CrossOrigin注解處理請(qǐng)求源碼解析,@CrossOrigin源碼解析主要分為兩個(gè)階段@CrossOrigin注釋的方法掃描注冊(cè),請(qǐng)求匹配@CrossOrigin注釋的方法,本文從源碼角度進(jìn)行解析,需要的朋友可以參考下

前言

@CrossOrigin源碼解析主要分為兩個(gè)階段:

① @CrossOrigin注釋的方法掃描注冊(cè)。

② 請(qǐng)求匹配@CrossOrigin注釋的方法。

本文針對(duì)第②階段從源碼角度進(jìn)行解析

請(qǐng)求匹配@CrossOrigin注釋的方法

請(qǐng)求匹配@CrossOrigin注釋的方法流程

在這里插入圖片描述

1) DispatcherServlet.doDispatch(...)、DispatcherServlet.getHandler(...)、AbstractHandlerMapping.getHandler(...)方法。

2) AbstractHandlerMethodMapping.getCorsConfiguration(...)方法。

① 若處理器為CorsConfigurationSource類型,獲取處理器CorsConfiguration配置作為基礎(chǔ)配置。

② 若處理方法為預(yù)處理方法,則返回默認(rèn)配置CorsConfiguration,其配置均為*。

③ 若處理方法非預(yù)處理方法,根據(jù)處理方法查找CorsConfiguration配置,同時(shí)與①所得配置進(jìn)行合并。

/**
 * 獲取CorsConfiguration.
 */
@Override
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
    // 若處理器為CorsConfigurationSource類型,直接獲取處理器CorsConfiguration配置.
    CorsConfiguration corsConfig = super.getCorsConfiguration(handler, request);
    if (handler instanceof HandlerMethod) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 請(qǐng)求方法是預(yù)處理方法.
        if (handlerMethod.equals(PREFLIGHT_AMBIGUOUS_MATCH)) {
            return AbstractHandlerMethodMapping.ALLOW_CORS_CONFIG;
        }
        // 請(qǐng)求方法非預(yù)處理方法.
        else {
            // 根據(jù)處理器查找CorsConfiguration配置.
            CorsConfiguration corsConfigFromMethod = this.mappingRegistry.getCorsConfiguration(handlerMethod);
            // 合并corsConfig和corsConfigFromMethod.
            corsConfig = (corsConfig != null ? corsConfig.combine(corsConfigFromMethod) : corsConfigFromMethod);
        }
    }
    return corsConfig;
}

3) AbstractHandlerMapping.getCorsConfiguration(...)方法。

若處理器為CorsConfigurationSource類型,獲取處理器CorsConfiguration配置作為基礎(chǔ)配置。

/**
 * 檢索給定處理程序的CORS配置.
 * @param handler 處理器.
 * @param request 當(dāng)前請(qǐng)求.
 * @return 處理程序的CORS配置,或者null(如果沒有).
 */
@Nullable
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
    Object resolvedHandler = handler;
    if (handler instanceof HandlerExecutionChain) {
        resolvedHandler = ((HandlerExecutionChain) handler).getHandler();
    }
    if (resolvedHandler instanceof CorsConfigurationSource) {
        return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request);
    }
    return null;
}

4) AbstractHandlerMethodMapping.MappingRegistry.getCorsConfiguration(...)方法。

① 從HandlerMethod解析實(shí)際的HandlerMethod。

② 根據(jù)HandlerMethod從corsLookup中獲取CorsConfiguration配置。

/**
 * 返回CORS配置.
 * 線程安全并發(fā)使用.
 */
public CorsConfiguration getCorsConfiguration(HandlerMethod handlerMethod) {
    // 解析實(shí)際的HandlerMethod.
    HandlerMethod original = handlerMethod.getResolvedFromHandlerMethod();
    // 從corsLookup中獲取CorsConfiguration配置.
    return this.corsLookup.get(original != null ? original : handlerMethod);
}

5) AbstractHandlerMapping.getCorsHandlerExecutionChain(...)方法。

① 若請(qǐng)求為預(yù)處理請(qǐng)求,AbstractHandlerMapping.PreFlightHandler作為處理器實(shí)現(xiàn)。

② 若請(qǐng)求非預(yù)處理請(qǐng)求,增加攔截器AbstractHandlerMapping.CorsInterceptor對(duì)請(qǐng)求進(jìn)行攔截處理。

/**
 * 為CORS相關(guān)處理更新HandlerExecutionChain.
 * 對(duì)于預(yù)處理請(qǐng)求,默認(rèn)實(shí)現(xiàn)用一個(gè)簡單的HttpRequestHandler替換所選的處理程序,
 * 	該處理程序調(diào)用配置的setCorsProcessor.
 * 對(duì)于實(shí)際的請(qǐng)求,默認(rèn)實(shí)現(xiàn)插入一個(gè)HandlerInterceptor,它進(jìn)行CORS相關(guān)的檢查并添加CORS頭.
 * @param request 當(dāng)前請(qǐng)求.
 * @param chain 處理鏈.
 * @param config 適用的CORS配置(可能是null).
 */
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
                                                             HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
    // 是CORS預(yù)處理請(qǐng)求.
    if (CorsUtils.isPreFlightRequest(request)) {
        HandlerInterceptor[] interceptors = chain.getInterceptors();
        chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
    }
    // 不是CORS預(yù)處理請(qǐng)求.		
    else {
        chain.addInterceptor(new CorsInterceptor(config));
    }
    return chain;
}

6) AbstractHandlerMapping.PreFlightHandler、AbstractHandlerMapping.CorsInterceptor類。

① 若請(qǐng)求非CORS請(qǐng)求,則跳過處理邏輯。

② 若響應(yīng)已包含Access-Control-Allow-Origin頭,則跳過處理邏輯。

③ 若請(qǐng)求與服務(wù)同源,則跳過處理邏輯。

④ 當(dāng)CORS配置為null時(shí),若請(qǐng)求為預(yù)處理請(qǐng)求,則拒絕請(qǐng)求,否則跳過處理邏輯。

/**
 * 處理請(qǐng)求.
 */
@Override
@SuppressWarnings("resource")
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
                              HttpServletResponse response) throws IOException {
    // 非CORS請(qǐng)求,不進(jìn)行處理.
    if (!CorsUtils.isCorsRequest(request)) {
        return true;
    }
    // 響應(yīng)已包含Access-Control-Allow-Origin,不進(jìn)行處理.
    ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
    if (responseHasCors(serverResponse)) {
        logger.debug("Skip CORS processing: response already contains \"Access-Control-Allow-Origin\" header");
        return true;
    }
    // 請(qǐng)求來自同源,不進(jìn)行處理.
    ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
    if (WebUtils.isSameOrigin(serverRequest)) {
        logger.debug("Skip CORS processing: request is from same origin");
        return true;
    }
    // 是否預(yù)處理請(qǐng)求.
    boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
    if (config == null) {
        if (preFlightRequest) {
            rejectRequest(serverResponse);
            return false;
        }
        else {
            return true;
        }
    }
	// 請(qǐng)求處理方法.
    return handleInternal(serverRequest, serverResponse, config, preFlightRequest);
}

① 獲取請(qǐng)求Origin頭,檢查并獲取允許的源。

② 針對(duì)Vary頭,增加值:Origin、Access-Control-Request-Method、Access-Control-Request-Headers。

③ 允許的源為空,則拒絕請(qǐng)求。

④ 獲取請(qǐng)求方法,檢查并獲取允許的方法。

⑤ 允許的方法為空,則拒絕請(qǐng)求。

⑥ 獲取請(qǐng)求頭,檢查并獲取請(qǐng)求的頭。

⑦ 若請(qǐng)求為預(yù)處理請(qǐng)求,且允許的頭為空,拒絕請(qǐng)求。

⑧ 設(shè)置Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Expose-Headers、Access-Control-Allow-Credentials、Access-Control-Max-Age。

/**
 * 請(qǐng)求處理方法.
 */
protected boolean handleInternal(ServerHttpRequest request, ServerHttpResponse response,
                                 CorsConfiguration config, boolean preFlightRequest) throws IOException {
    // 獲取請(qǐng)求的Origin頭.
    String requestOrigin = request.getHeaders().getOrigin();
    // 檢查并獲取允許源.
    String allowOrigin = checkOrigin(config, requestOrigin);
    HttpHeaders responseHeaders = response.getHeaders();
    // 增加Vary頭,其值為:Origin、Access-Control-Request-Method、Access-Control-Request-Headers.
    responseHeaders.addAll(HttpHeaders.VARY, Arrays.asList(HttpHeaders.ORIGIN,
                                                           HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS));
    // 允許源為空,則拒絕請(qǐng)求.
    if (allowOrigin == null) {
        logger.debug("Rejecting CORS request because '" + requestOrigin + "' origin is not allowed");
        rejectRequest(response);
        return false;
    }
    // 獲取請(qǐng)求方法.
    HttpMethod requestMethod = getMethodToUse(request, preFlightRequest);
    // 檢查并獲取允許的方法.
    List<HttpMethod> allowMethods = checkMethods(config, requestMethod);
    // 允許方法為空,則拒絕請(qǐng)求.
    if (allowMethods == null) {
        logger.debug("Rejecting CORS request because '" + requestMethod + "' request method is not allowed");
        rejectRequest(response);
        return false;
    }
    // 獲取請(qǐng)求頭.
    List<String> requestHeaders = getHeadersToUse(request, preFlightRequest);
    // 檢查并獲取請(qǐng)求的頭.
    List<String> allowHeaders = checkHeaders(config, requestHeaders);
    // 預(yù)處理請(qǐng)求,且允許的頭為空,拒絕請(qǐng)求.
    if (preFlightRequest && allowHeaders == null) {
        logger.debug("Rejecting CORS request because '" + requestHeaders + "' request headers are not allowed");
        rejectRequest(response);
        return false;
    }
    // 設(shè)置允許的源.
    responseHeaders.setAccessControlAllowOrigin(allowOrigin);
    // 設(shè)置Access-Control-Allow-Methods.
    if (preFlightRequest) {
        responseHeaders.setAccessControlAllowMethods(allowMethods);
    }
    // 設(shè)置Access-Control-Allow-Headers.
    if (preFlightRequest && !allowHeaders.isEmpty()) {
        responseHeaders.setAccessControlAllowHeaders(allowHeaders);
    }
    // 設(shè)置Access-Control-Expose-Headers.
    if (!CollectionUtils.isEmpty(config.getExposedHeaders())) {
        responseHeaders.setAccessControlExposeHeaders(config.getExposedHeaders());
    }
    // 設(shè)置Access-Control-Allow-Credentials.
    if (Boolean.TRUE.equals(config.getAllowCredentials())) {
        responseHeaders.setAccessControlAllowCredentials(true);
    }
    // 設(shè)置Access-Control-Max-Age.
    if (preFlightRequest && config.getMaxAge() != null) {
        responseHeaders.setAccessControlMaxAge(config.getMaxAge());
    }
    response.flush();
    return true;
}

總結(jié)

只有在了解實(shí)現(xiàn)細(xì)節(jié)的情況下,才能解決那些棘手的問題。隨著前后端分離程序變得極為普遍,@CrossOrigin的應(yīng)用變得尤為重要。

源碼解析基于spring-framework-5.0.5.RELEASE版本源碼。

若文中存在錯(cuò)誤和不足,歡迎指正!

到此這篇關(guān)于Spring的@CrossOrigin注解處理請(qǐng)求源碼解析的文章就介紹到這了,更多相關(guān)@CrossOrigin注解處理請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)經(jīng)典游戲黃金礦工的示例代碼

    Java實(shí)現(xiàn)經(jīng)典游戲黃金礦工的示例代碼

    《黃金礦工》游戲是一個(gè)經(jīng)典的抓金子小游戲,它可以鍛煉人的反應(yīng)能力。本文將用Java實(shí)現(xiàn)這一經(jīng)典的游戲,感興趣的小伙伴可以了解一下
    2022-02-02
  • java中char類型轉(zhuǎn)換成int類型的2種方法

    java中char類型轉(zhuǎn)換成int類型的2種方法

    這篇文章主要給大家介紹了關(guān)于java中char類型轉(zhuǎn)換成int類型的2種方法,因?yàn)閖ava是一門強(qiáng)類型語言,所以在數(shù)據(jù)運(yùn)算中會(huì)存在類型轉(zhuǎn)換,需要的朋友可以參考下
    2023-07-07
  • Java Volatile關(guān)鍵字你真的了解嗎

    Java Volatile關(guān)鍵字你真的了解嗎

    這篇文章主要為大家介紹了Java Volatile關(guān)鍵字,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • Java超詳細(xì)透徹講解接口

    Java超詳細(xì)透徹講解接口

    接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java接口,感興趣的朋友一起看看吧
    2022-05-05
  • Spring BeanUtils忽略空值拷貝的方法示例代碼

    Spring BeanUtils忽略空值拷貝的方法示例代碼

    本文用示例介紹Spring(SpringBoot)如何使用BeanUtils拷貝對(duì)象屬性忽略空置,忽略null值拷貝屬性的用法,代碼簡單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-03-03
  • SpringBoot+MySQL+Jpa實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的增刪改查和分頁詳解

    SpringBoot+MySQL+Jpa實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的增刪改查和分頁詳解

    這篇文章主要介紹了SpringBoot+MySQL+Jpa實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的增刪改查和分頁詳解,需要的朋友可以參考下
    2020-02-02
  • java程序代碼與文本對(duì)比實(shí)用工具簡介

    java程序代碼與文本對(duì)比實(shí)用工具簡介

    可以對(duì)兩段文本進(jìn)行對(duì)比,檢測/比較兩個(gè)文本有什么不同的差異,以便修改,常用于程序代碼,就是不需要人工查看,尤其是大文件,有幾百上千行的代碼,這時(shí)候就建議使用比較工具了,不用浪費(fèi)過多時(shí)間去尋找
    2021-09-09
  • Springboot 自定義校驗(yàn)代碼實(shí)例

    Springboot 自定義校驗(yàn)代碼實(shí)例

    這篇文章主要介紹了Springboot 自定義校驗(yàn)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • log4j2異步打印性能提升方式

    log4j2異步打印性能提升方式

    這篇文章主要介紹了log4j2異步打印性能提升方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring?AI集成DeepSeek實(shí)現(xiàn)流式輸出的操作方法

    Spring?AI集成DeepSeek實(shí)現(xiàn)流式輸出的操作方法

    本文介紹了如何在SpringBoot中使用Sse(Server-SentEvents)技術(shù)實(shí)現(xiàn)流式輸出,后端使用SpringMVC中的SseEmitter對(duì)象,前端使用EventSource對(duì)象監(jiān)聽SSE接口并展示數(shù)據(jù)流,通過這種方式可以提升用戶體驗(yàn),避免大模型響應(yīng)速度慢的問題,感興趣的朋友一起看看吧
    2025-03-03

最新評(píng)論

四子王旗| 永和县| 福贡县| 龙州县| 清丰县| 安徽省| 丰县| 浦城县| 乌审旗| 华坪县| 华安县| 溧水县| 扎囊县| 井陉县| 上虞市| 东海县| 横峰县| 酉阳| 宾川县| 健康| 厦门市| 建宁县| 七台河市| 滕州市| 华容县| 高密市| 杭州市| 商水县| 平定县| 榕江县| 商南县| 普宁市| 江都市| 巨鹿县| 淳化县| 临邑县| 偏关县| 屏南县| 商洛市| 宜都市| 横山县|