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

聊聊Spring?Cloud?Gateway過濾器精確控制異常返回問題

 更新時間:2021年11月25日 08:52:48   作者:程序員欣宸  
這篇文章主要介紹了Spring?Cloud?Gateway過濾器精確控制異常返回問題,本篇任務(wù)就是分析上述現(xiàn)象的原因,通過閱讀源碼搞清楚返回碼和響應(yīng)body生成的具體邏輯,需要的朋友可以參考下

歡迎訪問我的GitHub

這里分類和匯總了欣宸的全部原創(chuàng)(含配套源碼):https://github.com/zq2599/blog_demos

本篇概覽在《Spring Cloud Gateway修改請求和響應(yīng)body的內(nèi)容》一文中,咱們通過filter成功修改請求body的內(nèi)容,當時留下個問題:在filter中如果發(fā)生異常(例如請求參數(shù)不合法),拋出異常信息的時候,調(diào)用方收到的返回碼和body都是Spring Cloud Gateway框架處理后的,調(diào)用方無法根據(jù)這些內(nèi)容知道真正的錯誤原因,如下圖:

本篇任務(wù)就是分析上述現(xiàn)象的原因,通過閱讀源碼搞清楚返回碼和響應(yīng)body生成的具體邏輯

  • 這里將分析結(jié)果提前小結(jié)出來,如果您很忙碌沒太多時間卻又想知道最終原因,直接關(guān)注以下小結(jié)即可:
  1. Spring Cloud Gateway應(yīng)用中,有個ErrorAttributes類型的bean,它的getErrorAttributes方法返回了一個map
  2. 應(yīng)用拋出異常時,返回碼來自上述map的status的值,返回body是整個map序列化的結(jié)果
  3. 默認情況下ErrorAttributes的實現(xiàn)類是DefaultErrorAttributes
  • 再看上述map的status值(也就是response的返回碼),在DefaultErrorAttributes是如何生成的:

先看異常對象是不是ResponseStatusException類型

  1. 如果是ResponseStatusException類型,就調(diào)用異常對象的getStatus方法作為返回值
  2. 如果不是ResponseStatusException類型,再看異常類有沒有ResponseStatus注解,
  3. 如果有,就取注解的code屬性作為返回值
  4. 如果異常對象既不是ResponseStatusException類型,也沒有ResponseStatus注解,就返回500

最后看map的message字段(也就是response body的message字段),在DefaultErrorAttributes是如何生成的:

  1. 異常對象是不是BindingResult類型
  2. 如果不是BindingResult類型,就看是不是ResponseStatusException類型
  3. 如果是,就用getReason作為返回值
  4. 如果也不是ResponseStatusException類型,就看異常類有沒有ResponseStatus注解,如果有就取該注解的reason屬性作為返回值
  5. 如果通過注解取得的reason也無效,就返回異常的getMessage字段

上述內(nèi)容就是本篇精華,但是并未包含分析過程,如果您對Spring Cloud源碼感興趣,請允許欣宸陪伴您來一次短暫的源碼閱讀之旅

Spring Cloud Gateway錯誤處理源碼

首先要看的是配置類ErrorWebFluxAutoConfiguration.java,這里面向spring注冊了兩個實例,每個都非常重要,咱們先關(guān)注第一個,也就是說ErrorWebExceptionHandler的實現(xiàn)類是DefaultErrorWebExceptionHandler:

處理異常時,會通過FluxOnErrorResume調(diào)用到這個ErrorWebExceptionHandler的handle方法處理,該方法在其父類AbstractErrorWebExceptionHandler.java中,如下圖,紅框位置的代碼是關(guān)鍵,異常返回內(nèi)容就是在這里決定的:

展開這個getRoutingFunction方法,可見會調(diào)用renderErrorResponse來處理響應(yīng):

@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
	}

打開renderErrorResponse方法,如下所示,真相大白了!

protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
  // 取出所有錯誤信息
  Map<String, Object> error = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
  
  // 構(gòu)造返回的所有信息 
  return ServerResponse
           // 控制返回碼
           .status(getHttpStatus(error))
           // 控制返回ContentType
           .contentType(MediaType.APPLICATION_JSON)
           // 控制返回內(nèi)容
           .body(BodyInserters.fromValue(error));
}

通過上述代碼,咱們得到兩個重要結(jié)論:

  • 返回給調(diào)用方的狀態(tài)碼,取決于getHttpStatus方法的返回值
  • 返回給調(diào)用方的body,取決于error的內(nèi)容

都已經(jīng)讀到了這里,自然要看看getHttpStatus的內(nèi)部,如下所示,status來自入?yún)ⅲ?/p>

protected int getHttpStatus(Map<String, Object> errorAttributes) {
  return (int) errorAttributes.get("status");
}
  • 至此,咱們可以得出一個結(jié)論:getErrorAttributes方法的返回值是決定返回碼和返回body的關(guān)鍵!
  • 來看看這個getErrorAttributes方法的廬山真面吧,在DefaultErrorAttributes.java中(回憶剛才看ErrorWebFluxAutoConfiguration.java的時候,前面曾提到里面的東西都很重要,也包括errorAttributes方法):
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = this.getErrorAttributes(request, options.isIncluded(Include.STACK_TRACE));
        if (Boolean.TRUE.equals(this.includeException)) {
            options = options.including(new Include[]{Include.EXCEPTION});
        }

        if (!options.isIncluded(Include.EXCEPTION)) {
            errorAttributes.remove("exception");
        }

        if (!options.isIncluded(Include.STACK_TRACE)) {
            errorAttributes.remove("trace");
        }

        if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
            errorAttributes.put("message", "");
        }

        if (!options.isIncluded(Include.BINDING_ERRORS)) {
            errorAttributes.remove("errors");
        }

        return errorAttributes;
    }

篇幅所限,就不再展開上述代碼了,直接上結(jié)果吧:

  • 返回碼來自determineHttpStatus的返回
  • message字段來自determineMessage的返回打開determineHttpStatus方法,終極答案揭曉,請關(guān)注中文注釋:
private HttpStatus determineHttpStatus(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation) {
        // 異常對象是不是ResponseStatusException類型
        return error instanceof ResponseStatusException 
        // 如果是ResponseStatusException類型,就調(diào)用異常對象的getStatus方法作為返回值
        ? ((ResponseStatusException)error).getStatus() 
        // 如果不是ResponseStatusException類型,再看異常類有沒有ResponseStatus注解,
        // 如果有,就取注解的code屬性作為返回值
        : (HttpStatus)responseStatusAnnotation.getValue("code", HttpStatus.class)
        // 如果異常對象既不是ResponseStatusException類型,也沒有ResponseStatus注解,就返回500
        .orElse(HttpStatus.INTERNAL_SERVER_ERROR);
    }

另外,message字段的內(nèi)容也確定了:

 private String determineMessage(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation) {
        // 異常對象是不是BindingResult類型
        if (error instanceof BindingResult) {
            // 如果是,就用getMessage作為返回值
            return error.getMessage();
        } 
        // 如果不是BindingResult類型,就看是不是ResponseStatusException類型
        else if (error instanceof ResponseStatusException) {
            // 如果是,就用getReason作為返回值
            return ((ResponseStatusException)error).getReason();
        } else {
            // 如果也不是ResponseStatusException類型,
            // 就看異常類有沒有ResponseStatus注解,如果有就取該注解的reason屬性作為返回值
            String reason = (String)responseStatusAnnotation.getValue("reason", String.class).orElse("");
            if (StringUtils.hasText(reason)) {
                return reason;
            } else {
                // 如果通過注解取得的reason也無效,就返回異常的getMessage字段
                return error.getMessage() != null ? error.getMessage() : "";
            }
        }
    }
  • 至此,源碼分析已完成,最終的返回碼和返回內(nèi)容究竟如何控制,相信聰明的您心里應(yīng)該有數(shù)了,下一篇《實戰(zhàn)篇》咱們趁熱打鐵,寫代碼試試精確控制返回碼和返回內(nèi)容
  • 提前劇透,接下來的《實戰(zhàn)篇》會有以下內(nèi)容呈現(xiàn):
  • 直接了當,控制返回碼和body中的error字段
  • 小小攔路虎,見招拆招
  • 簡單易用,通過注解控制返回信息
  • 終極方案,完全定制返回內(nèi)容

到此這篇關(guān)于Spring?Cloud?Gateway過濾器精確控制異常返回(分析篇)的文章就介紹到這了,更多相關(guān)Spring?Cloud?Gateway過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中HandlerMethod類源碼詳細解析

    Spring中HandlerMethod類源碼詳細解析

    這篇文章主要介紹了Spring中HandlerMethod類源碼詳細解析,HandlerMethod類用于封裝控制器方法信息,包含類信息、方法Method對象、參數(shù)、注解等信息,具體的接口請求是可以根據(jù)封裝的信息調(diào)用具體的方法來執(zhí)行業(yè)務(wù)邏輯,需要的朋友可以參考下
    2023-11-11
  • Spring boot實現(xiàn)熱部署的兩種方式詳解

    Spring boot實現(xiàn)熱部署的兩種方式詳解

    這篇文章主要介紹了Spring boot實現(xiàn)熱部署的兩種方式,這兩種方法分別是使用 Spring Loaded和使用spring-boot-devtools進行熱部署,文中給出了詳細示例代碼和介紹,需要的朋友可以參考學(xué)習,下面來一起看看吧。
    2017-04-04
  • idea gradle項目復(fù)制依賴小技巧(推薦)

    idea gradle項目復(fù)制依賴小技巧(推薦)

    這篇文章主要介紹了idea gradle項目復(fù)制依賴小技巧,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 遠程連接Jedis和整合SpringBoot的詳細過程

    遠程連接Jedis和整合SpringBoot的詳細過程

    這篇文章主要介紹了遠程連接Jedis和整合SpringBoot的詳細過程,本文通過圖文實例相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • 使用restTemplate.postForEntity()的問題

    使用restTemplate.postForEntity()的問題

    這篇文章主要介紹了使用restTemplate.postForEntity()的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 分模塊構(gòu)建Maven工程的方法步驟

    分模塊構(gòu)建Maven工程的方法步驟

    這篇文章主要介紹了分模塊構(gòu)建Maven工程的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2020-10-10
  • Java?Lambda表達式常用的函數(shù)式接口

    Java?Lambda表達式常用的函數(shù)式接口

    這篇文章主要介紹了Java?Lambda表達式常用的函數(shù)式接口,文章基于Java?Lambda表達式展開對常用的函數(shù)式接口的介紹,具有一的的參考價值需要的小伙伴可以參考一下
    2022-04-04
  • Spring boot + thymeleaf 后端直接給onclick函數(shù)賦值的實現(xiàn)代碼

    Spring boot + thymeleaf 后端直接給onclick函數(shù)賦值的實現(xiàn)代碼

    這篇文章主要介紹了Spring boot + thymeleaf 后端直接給onclick函數(shù)賦值的實現(xiàn)代碼,需要的朋友可以參考下
    2017-06-06
  • 使用純Java實現(xiàn)一個WebSSH項目的示例代碼

    使用純Java實現(xiàn)一個WebSSH項目的示例代碼

    這篇文章主要介紹了使用純Java實現(xiàn)一個WebSSH項目,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2020-03-03
  • java數(shù)組基礎(chǔ)詳解

    java數(shù)組基礎(chǔ)詳解

    這篇文章主要介紹了Java數(shù)組基礎(chǔ)詳解,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11

最新評論