成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

HttpInterceptor 攔截器 - 網(wǎng)絡(luò)請(qǐng)求超時(shí)與重試的簡(jiǎn)單實(shí)現(xiàn)

stonezhu / 3371人閱讀

摘要:對(duì)象表示攔截器鏈表中的下一個(gè)攔截器。至此,攔截器只會(huì)再重試到最大次數(shù)還是失敗的情況下拋出超時(shí)錯(cuò)誤。完成上述步驟,一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求超時(shí)與重試的攔截器便實(shí)現(xiàn)了。

...

攔截器Angular項(xiàng)目中其實(shí)有著十分重要的地位,攔截器可以統(tǒng)一對(duì) HTTP 請(qǐng)求進(jìn)行攔截處理,我們可以在每個(gè)請(qǐng)求體或者響應(yīng)后對(duì)應(yīng)的流添加一系列動(dòng)作或者處理數(shù)據(jù),再返回給使用者調(diào)用。

每個(gè) API 調(diào)用的時(shí)候都不可避免的會(huì)出現(xiàn)網(wǎng)絡(luò)超時(shí)的情況,但是這種情況是多變的,可能是網(wǎng)絡(luò)問(wèn)題,也有可能是服務(wù)端問(wèn)題,盡管如此,我們也只需對(duì)網(wǎng)絡(luò)超時(shí)這一種情況來(lái)進(jìn)行處理。

套殼 按照慣例寫一個(gè)攔截器的殼
import {
    HttpInterceptor,
    HttpRequest,
    HttpHandler,
    HttpEvent
} from "@angular/common/http"
import { Injectable } from "@angular/core"
import { Observable } from "rxjs"
import { timeout } from "rxjs/operators"

/** 攔截器 - 超時(shí)以及重試設(shè)置 */
@Injectable()
export class TimeoutInterceptor implements HttpInterceptor {

    constructor() { }

    intercept(req: HttpRequest, next: HttpHandler): Observable> {
        return next.handle(req)
    }
}
加入超時(shí)處理 超時(shí)

rxjs確實(shí)功能強(qiáng)大,這里的超時(shí)我們只需要使用timeout操作符便可以實(shí)現(xiàn)。這里的超時(shí)處理邏輯是掛到next.handle()返回的可觀察對(duì)象中。

next 對(duì)象表示攔截器鏈表中的下一個(gè)攔截器。 這個(gè)鏈表中的最后一個(gè) next 對(duì)象就是 HttpClient 的后端處理器(backend handler),它會(huì)把請(qǐng)求發(fā)給服務(wù)器,并接收服務(wù)器的響應(yīng)。
大多數(shù)的攔截器都會(huì)調(diào)用 next.handle(),以便這個(gè)請(qǐng)求流能走到下一個(gè)攔截器,并最終傳給后端處理器。

先在類外部定義一個(gè)超時(shí)時(shí)限

/** 超時(shí)時(shí)間 */
const DEFAULTTIMEOUT = 8000

在攔截器主函數(shù)handle流中加入操作符

return next.handle(req).pipe(
    timeout(DEFAULTTIMEOUT)
)

其實(shí)這樣就實(shí)現(xiàn)了超時(shí)攔截器,當(dāng)超過(guò)設(shè)定的時(shí)間還沒(méi)有響應(yīng)數(shù)據(jù)的時(shí)候,handle流便會(huì)在拋出相應(yīng)的超時(shí)錯(cuò)誤。

捕獲超時(shí)

在超時(shí)錯(cuò)誤發(fā)生后,我們可能需要第一時(shí)間捕獲到以便給用戶一個(gè)提示。這里可以直接使用catchError操作符。

在攔截器主函數(shù)handle流中加入操作符

return next.handle(req).pipe(
    //... 已有的代碼忽略
    catchError((err: HttpErrorResponse) => {
        this.nzNotificationService.error("網(wǎng)絡(luò)超時(shí)","請(qǐng)重試")
        return throwError(err)
    })
)

handle需要返回一個(gè)可觀察對(duì)象,所以我們順便把捕獲的錯(cuò)誤返回。這樣一來(lái),便可以在捕獲到超時(shí)的時(shí)候顯示一個(gè)簡(jiǎn)單的提示。

超時(shí)重試

一般來(lái)說(shuō),超時(shí)出現(xiàn)的情況是不確定的,即使多了提示,有些請(qǐng)求用戶也沒(méi)有其他的動(dòng)作去重試,只能刷新頁(yè)面,那此時(shí)重新請(qǐng)求就顯得重要了,我們可以在捕獲到超時(shí)請(qǐng)求之后對(duì)這個(gè)請(qǐng)求再進(jìn)行固定次數(shù)的重試,避免某些情況的超時(shí)影響用戶體驗(yàn)。

對(duì)流進(jìn)行多次重試,可以使用retryWhen操作符。

retryWhen操作符接受一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)會(huì)接受一個(gè)由一組錯(cuò)誤組成的Observable,我們可以針對(duì)這個(gè)Observable做一些節(jié)奏控制來(lái)促動(dòng)重試動(dòng)作,然后在函數(shù)中返回這個(gè)可觀察對(duì)象。

一個(gè)簡(jiǎn)單的retryWhen組成:

retryWhen(err$ => {
    return err$.pipe(
        //一些節(jié)奏控制
        ...
    )
})

如此以來(lái),我們就可以直接使用此操作符來(lái)實(shí)現(xiàn)了。

添加retryWhen重試

我們?cè)?b>next.handle流掛上retryWhen操作符

return next.handle(req).pipe(
    //... 已有的代碼忽略
    retryWhen(err$ => {
        return err$
    })
)

其實(shí)此時(shí)就已經(jīng)實(shí)現(xiàn)了重試機(jī)制,但是運(yùn)行結(jié)果你會(huì)發(fā)現(xiàn),當(dāng)超時(shí)錯(cuò)誤永遠(yuǎn)存在時(shí),重試的次數(shù)是無(wú)限的,也就是程序會(huì)不斷得請(qǐng)求,因?yàn)槲覀冞€沒(méi)有做任何的節(jié)奏控制。

那么,我們就需要先確定一下重試的節(jié)奏,比如最大的重試次數(shù)、每次延遲多久重試、重試上限次數(shù)還是失敗了的處理等等。那就簡(jiǎn)單處理提到的這3個(gè)情況吧。

重試最大次數(shù)

既然retryWhenerr$是一個(gè)錯(cuò)誤組成的流,那么每一次超時(shí)重試失敗后,err$便會(huì)推動(dòng)一次數(shù)據(jù),我們可以使用scan操作符來(lái)累計(jì)獲取重試失敗的次數(shù),以此來(lái)控制重試的最大次數(shù)。

scan操作符接受兩個(gè)參數(shù),第一個(gè)是累加函數(shù),可以在函數(shù)中獲取上一次scan的累加值以及所在流的數(shù)據(jù),第二個(gè)值接受一個(gè)scan的初始累加值,所以可以很輕松地獲取重試錯(cuò)誤的次數(shù)。

在攔截器類外部定義一個(gè)最大重試次數(shù):

/** 最大重試次數(shù) */
const MAXRETRYCOUNT = 3

我們?cè)?b>retryWhen中掛上scan操作符

return next.handle(req).pipe(
    //... 已有的代碼忽略
    retryWhen(err$ => {
        return err$.pipe(
            scan((errCount, err) => {
                if (errCount >= MAXRETRYCOUNT) {
                    throw err
                }
                return errCount + 1
            }, 0)
        )
    })
)

scan中,我們獲取了累加值(errCount,初始為0 ),判斷是否大于上限,如果大于便直接拋出超時(shí)錯(cuò)誤(err),如果小于便返回累加值 +1。至此,攔截器只會(huì)再重試到最大次數(shù)還是失敗的情況下拋出超時(shí)錯(cuò)誤。

延遲重試

重試最好加上延遲,避免某些場(chǎng)景下一定請(qǐng)求錯(cuò)誤的情況,比如服務(wù)器的某些請(qǐng)求過(guò)濾。延遲十分簡(jiǎn)單,只需要在err$掛上delay操作符,流的推動(dòng)便會(huì)以一定的間隔實(shí)行。

return next.handle(req).pipe(
    //... 已有的代碼忽略
    retryWhen(err$ => {
        return err$.pipe(
            //... 已有的代碼忽略
            delay(1000)
        )
    })
)
重試的友好提示

可能有的時(shí)候網(wǎng)絡(luò)太慢,或者重試次數(shù)設(shè)置得比較大,這樣在請(qǐng)求重試的時(shí)候會(huì)耗時(shí)比較久,而用戶是不知道此時(shí)正在重試的,所以加一個(gè)友好的提示可以增加用戶體驗(yàn)。

而添加提示是屬于比較透明或者說(shuō)屬于副作用動(dòng)作,此時(shí)我們可以直接使用tap操作符來(lái)進(jìn)行操作。由于是掛到scan之后,所以在tap中獲取到的就是重試的累加值。

return next.handle(req).pipe(
    //... 已有的代碼忽略
    retryWhen(err$ => {
        return err$.pipe(
            //... 已有的代碼忽略
            tap(errCount => {
                if(errCount == 1){
                    //第一次重試時(shí)顯示友好信息
                    this.nzNotificationService.info("網(wǎng)絡(luò)超時(shí)","正在重新請(qǐng)求中...")
                }
            })
        )
    })
)

這樣當(dāng)?shù)谝淮沃匦抡?qǐng)求時(shí),我們便給出明確的提示。

修改捕獲錯(cuò)誤(catchError)的順序

前面我們?cè)跊](méi)有重試功能之前設(shè)置了捕獲錯(cuò)誤,并給出提示。由于后面加了重試功能,故捕獲錯(cuò)誤的操作需要掛到重試之后,這樣一來(lái),才可以在全部重試完成后仍然失敗的情況下提示用戶,而不是每次重試都給出捕獲到的錯(cuò)誤提示。

return next.handle(req).pipe(
    timeout( ... ),
    retryWhen( ... ),
    catchError( ... )
)

完成上述步驟,一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求超時(shí)與重試的攔截器便實(shí)現(xiàn)了。完整的代碼如下:

import {
    HttpInterceptor,
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpErrorResponse
} from "@angular/common/http"
import { Injectable } from "@angular/core"
import { 
    Observable, 
    throwError 
} from "rxjs"
import { 
    timeout, 
    delay, 
    retryWhen, 
    scan, 
    tap, 
    catchError 
} from "rxjs/operators"
import { NzNotificationService } from "ng-zorro-antd"

/** 超時(shí)時(shí)間 */
const DEFAULTTIMEOUT = 8
/** 最大重試次數(shù) */
const MAXRETRYCOUNT = 3

//攔截器 - 超時(shí)以及重試設(shè)置
@Injectable()
export class TimeoutInterceptor implements HttpInterceptor {

    constructor(
        private nzNotificationService:NzNotificationService
    ) { }

    intercept(req: HttpRequest, next: HttpHandler): Observable> {
        return next.handle(req).pipe(
            timeout(DEFAULTTIMEOUT),
            retryWhen(err$ => {
                //重試 節(jié)奏控制器
                return err$.pipe(
                    scan((errCount, err) => {
                        if (errCount >= MAXRETRYCOUNT) {
                            throw err
                        }
                        return errCount + 1
                    }, 0),
                    delay(1000),
                    tap(errCount => {
                        //副作用
                        if(errCount == 1){
                            //第一次重試時(shí)顯示友好信息
                            this.nzNotificationService.info("網(wǎng)絡(luò)超時(shí)","正在重新請(qǐng)求中...")
                        }
                    })
                )
            }),
            catchError((err: HttpErrorResponse) => {
                this.nzNotificationService.error("網(wǎng)絡(luò)超時(shí)","請(qǐng)重試")
                return throwError(err)
            })
        )
    }   
}

詳細(xì)攔截器說(shuō)明請(qǐng)前往官網(wǎng)文檔:攔截請(qǐng)求和響應(yīng)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98649.html

相關(guān)文章

  • Spring 指南(spring-retry)

    摘要:包含一些狀態(tài)來(lái)決定是重試還是中止,但是這個(gè)狀態(tài)位于堆棧上,不需要將它存儲(chǔ)在全局的任何位置,因此我們將此稱為無(wú)狀態(tài)重試。將拋出原始異常,除非在有狀態(tài)的情況下,當(dāng)沒(méi)有可用的恢復(fù),在這種情況下,它將拋出。 spring-retry 該項(xiàng)目為Spring應(yīng)用程序提供聲明式重試支持,它用于Spring Batch、Spring Integration、Apache Hadoop的Spring(以...

    xiaotianyi 評(píng)論0 收藏0
  • 我們?nèi)绾卧贚inkerd 2.2里設(shè)計(jì)重試

    摘要:在這篇文章中,我們描述了我們?nèi)绾卧诶镌O(shè)計(jì)重試,使能夠在最小化風(fēng)險(xiǎn)的同時(shí),自動(dòng)提高系統(tǒng)可靠性。配置重試的最常用方法,是指定在放棄之前執(zhí)行的最大重試次數(shù)。超時(shí)時(shí),將取消請(qǐng)求并返回響應(yīng)。但是在上面的服務(wù)配置文件中,我們將在服務(wù)器端指定重試政策。 showImg(https://segmentfault.com/img/bVbo113?w=4400&h=1007);作者:Alex Leong ...

    Mike617 評(píng)論0 收藏0
  • RestTemplate集成Ribbbon

    摘要:的類圖如下主要根據(jù)創(chuàng)建擴(kuò)展了,創(chuàng)建攔截的,這里會(huì)設(shè)置攔截器,這是集成的核心,當(dāng)發(fā)起請(qǐng)求調(diào)用的時(shí)候,會(huì)先經(jīng)過(guò)攔截器,然后才真正發(fā)起請(qǐng)求。和是配合使用的,最大重試次數(shù)是針對(duì)每一個(gè)的,如果設(shè)置,這樣觸發(fā)最大重試次數(shù)就是次。 上一篇文章我們分析了ribbon的核心原理,接下來(lái)我們來(lái)看看springcloud是如何集成ribbon的,不同的springcloud的組件(feign,zuul,Re...

    wall2flower 評(píng)論0 收藏0
  • SpringCloud升級(jí)之路2020.0.x版-37. 實(shí)現(xiàn)異步的客戶端封裝配置管理的意義與設(shè)計(jì)

    摘要:對(duì)于異步的請(qǐng)求,使用的是異步客戶端即。要實(shí)現(xiàn)的配置設(shè)計(jì)以及使用舉例要實(shí)現(xiàn)的配置設(shè)計(jì)以及使用舉例首先,我們要實(shí)現(xiàn)的,其包含三個(gè)重試重試的要在負(fù)載均衡之前,因?yàn)橹卦嚨臅r(shí)候,我們會(huì)從負(fù)載均衡器獲取另一個(gè)實(shí)例進(jìn)行重試,而不是在同一個(gè)實(shí)例上重試多次。 本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent 為何需要封裝異步 HT...

    fxp 評(píng)論0 收藏0
  • 簽發(fā)的用戶認(rèn)證token超時(shí)刷新策略

    摘要:簽發(fā)的用戶認(rèn)證超時(shí)刷新策略這個(gè)模塊分離至項(xiàng)目權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺(jué)那樣太長(zhǎng)了找不到重點(diǎn),分離出來(lái)要好點(diǎn)。這樣在有效期過(guò)后的時(shí)間段內(nèi)可以申請(qǐng)刷新。 簽發(fā)的用戶認(rèn)證token超時(shí)刷新策略 這個(gè)模塊分離至項(xiàng)目api權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺(jué)那樣太長(zhǎng)了找不到重點(diǎn),分離出來(lái)要好點(diǎn)。 對(duì)于登錄的用戶簽發(fā)其對(duì)應(yīng)的jwt,我們?cè)趈wt設(shè)置他的固定有效期時(shí)間,在有效期內(nèi)用戶攜帶jw...

    e10101 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<