亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

聊聊Spring?Cloud?Gateway過(guò)濾器精確控制異常返回問(wèn)題

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

歡迎訪(fǎng)問(wèn)我的GitHub

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

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

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

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

先看異常對(duì)象是不是ResponseStatusException類(lèi)型

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

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

  1. 異常對(duì)象是不是BindingResult類(lèi)型
  2. 如果不是BindingResult類(lèi)型,就看是不是ResponseStatusException類(lèi)型
  3. 如果是,就用getReason作為返回值
  4. 如果也不是ResponseStatusException類(lèi)型,就看異常類(lèi)有沒(méi)有ResponseStatus注解,如果有就取該注解的reason屬性作為返回值
  5. 如果通過(guò)注解取得的reason也無(wú)效,就返回異常的getMessage字段

上述內(nèi)容就是本篇精華,但是并未包含分析過(guò)程,如果您對(duì)Spring Cloud源碼感興趣,請(qǐng)?jiān)试S欣宸陪伴您來(lái)一次短暫的源碼閱讀之旅

Spring Cloud Gateway錯(cuò)誤處理源碼

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

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

展開(kāi)這個(gè)getRoutingFunction方法,可見(jiàn)會(huì)調(diào)用renderErrorResponse來(lái)處理響應(yīng):

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

打開(kāi)renderErrorResponse方法,如下所示,真相大白了!

protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
  // 取出所有錯(cuò)誤信息
  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));
}

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

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

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

protected int getHttpStatus(Map<String, Object> errorAttributes) {
  return (int) errorAttributes.get("status");
}
  • 至此,咱們可以得出一個(gè)結(jié)論:getErrorAttributes方法的返回值是決定返回碼和返回body的關(guān)鍵!
  • 來(lái)看看這個(gè)getErrorAttributes方法的廬山真面吧,在DefaultErrorAttributes.java中(回憶剛才看ErrorWebFluxAutoConfiguration.java的時(shí)候,前面曾提到里面的東西都很重要,也包括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;
    }

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

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

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

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

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

相關(guān)文章

  • Spring中HandlerMethod類(lèi)源碼詳細(xì)解析

    Spring中HandlerMethod類(lèi)源碼詳細(xì)解析

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

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

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

    idea gradle項(xiàng)目復(fù)制依賴(lài)小技巧(推薦)

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

    遠(yuǎn)程連接Jedis和整合SpringBoot的詳細(xì)過(guò)程

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

    使用restTemplate.postForEntity()的問(wèn)題

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論