日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

.NET Core HttpClient请求异常分析

發(fā)布時(shí)間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core HttpClient请求异常分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
【導(dǎo)讀】最近項(xiàng)目上每天間斷性捕獲到HttpClient請(qǐng)求異常,感覺(jué)有點(diǎn)奇怪,于是乎觀察了兩三天,通過(guò)日志以及對(duì)接方溝通確認(rèn)等等,查看對(duì)應(yīng)版本源碼,嘗試添加部分配置發(fā)布后,觀察十幾小時(shí)暫無(wú)異常情況出現(xiàn),貌似問(wèn)題已得到解決,若有后續(xù)繼續(xù)更新

HttpClient來(lái)源:netstandard2.0

場(chǎng)景:將相關(guān)廠家地磁設(shè)備(停車(chē)進(jìn)出場(chǎng))推送數(shù)據(jù),轉(zhuǎn)發(fā)至對(duì)接方。

最近一個(gè)星期經(jīng)過(guò)觀察會(huì)出現(xiàn)兩種異常情況,一種是請(qǐng)求連接操作被取消,另外一種則是請(qǐng)求處理過(guò)程中操作被取消,具體異常信息請(qǐng)見(jiàn)如下圖

我們知道HttpClient默認(rèn)超時(shí)時(shí)間為100s,但項(xiàng)目默認(rèn)設(shè)置請(qǐng)求超時(shí)時(shí)間為30s,初次分析異常情況來(lái)看,請(qǐng)求超時(shí)導(dǎo)致請(qǐng)求連接被取消異常,首先我telnet對(duì)接方端口通暢,于是乎與對(duì)接方交涉,是否存在從請(qǐng)求到對(duì)接方接口有額外前置處理,以及網(wǎng)絡(luò)是否存在波動(dòng)等等,排查得知相關(guān)猜測(cè)都予以否決,網(wǎng)絡(luò)無(wú)任何問(wèn)題

問(wèn)題排查分析

既然網(wǎng)絡(luò)沒(méi)有任何問(wèn)題,難道是對(duì)接方即服務(wù)端處理數(shù)據(jù)量巨大,導(dǎo)致請(qǐng)求應(yīng)答超時(shí)?于是乎對(duì)接方甩出幾張最近消息接收數(shù)據(jù)

從上述兩張圖來(lái)看,最多的一天也才90來(lái)萬(wàn),最近幾天請(qǐng)求失敗的數(shù)據(jù)大概2百來(lái)?xiàng)l,從我們平臺(tái)打印日志來(lái)看,每秒請(qǐng)求大致是10個(gè)左右,通過(guò)HTTP對(duì)接完全可以承載。

然后,因?yàn)槲覀儗?shù)據(jù)(JSON,數(shù)據(jù)大小幾乎可以忽略不計(jì))轉(zhuǎn)發(fā)到對(duì)接方,對(duì)接方拿到數(shù)據(jù)后不會(huì)進(jìn)行任何額外處理,直接存儲(chǔ),所以我們請(qǐng)求超時(shí)時(shí)間30s,怎么會(huì)導(dǎo)致超時(shí)而引發(fā)異常呢?很奇怪

沒(méi)轍了,只能拿起終極武器,tcp抓包分析,重新學(xué)習(xí)了tcp/ip協(xié)議族一波

WireShark抓包分析

為打開(kāi)分析上述pcap文件,提前安裝抓包軟件WireShark最新版本,由于軟件項(xiàng)目部署在Linux上,我們通過(guò)如下命令進(jìn)行抓包

tcpdump?-i?any?port?1443?-w?exception.pcap

從如下抓包信息可以直接知道,對(duì)接方使用了HTTPS協(xié)議,具體請(qǐng)看如下圖

如圖來(lái)源于CSDN

默認(rèn)打開(kāi)如上圖所示,其中time為時(shí)間戳,為找到我們指定時(shí)間點(diǎn)(2021-06-04 15:46:17.296),通過(guò)tab:視圖-時(shí)間顯示格式-日期和時(shí)間

接下來(lái)我們找到包文件中導(dǎo)致請(qǐng)求被取消異常的具體時(shí)間節(jié)點(diǎn)(2021-06-04 15:46:17.296)

?在TCP協(xié)議中RST表示復(fù)位,用于異常時(shí)關(guān)閉連接。在發(fā)送RST包關(guān)閉連接時(shí),不必等待緩沖區(qū)的包都發(fā)出去,直接丟棄緩沖區(qū)的包而發(fā)送RST包。而接收端收到RST包后,也不必發(fā)送ACK包來(lái)確認(rèn)。

好像有點(diǎn)眉頭了,繼續(xù)往下看

好家伙,結(jié)合這張圖來(lái)看,基本上可以得出結(jié)論:原來(lái)是我們平臺(tái)主動(dòng)重置了連接,緊接著又開(kāi)始了多次進(jìn)行三次握手連接即(SYN、SYN/ACK、ACK)

示例代碼分析

推送邏輯是在類(lèi)庫(kù)中使用HttpClient,所以沒(méi)有使用HttpClientFactory,因此定義靜態(tài)變量來(lái)使用HttpClient,而非每一個(gè)請(qǐng)求就實(shí)例化一個(gè)HttpClient

接下來(lái)我們來(lái)詳細(xì)分析項(xiàng)目示例代碼并對(duì)其進(jìn)行改進(jìn)

static?class?Program {static?HttpClient?httpClient?=?CreateHttpClient();static?Program(){ServicePointManager.SecurityProtocol?=?SecurityProtocolType.Tls12;ServicePointManager.ServerCertificateValidationCallback?=?(message,?cert,?chain,?error)?=>?true,}static?async?Task?Main(string[]?args){await?httpClient.PostAsync("",?new?StringContent(""));}static?HttpClient?CreateHttpClient(){var?client?=?new?HttpClient(new?HttpClientHandler{ServerCertificateCustomValidationCallback?=?(message,?cert,?chain,?error)?=>?true}){Timeout?=?TimeSpan.FromSeconds(30)};client.DefaultRequestHeaders.Accept.Clear();client.DefaultRequestHeaders.Accept.Add(new?MediaTypeWithQualityHeaderValue("application/json"));client.DefaultRequestHeaders.Add("ContentType",?"application/json");return?client;} }

若對(duì)接方僅使用HTTPS協(xié)議,無(wú)需驗(yàn)證證書(shū),最好是忽略證書(shū)驗(yàn)證,否則有可能會(huì)引起建立驗(yàn)證證書(shū)連接異常,即添加

ServerCertificateCustomValidationCallback?=?(message,?cert,?chain,?error)?=>?true

我們觀察上述代碼,有兩個(gè)地方都對(duì)證書(shū)驗(yàn)證進(jìn)行了設(shè)置,一個(gè)是在靜態(tài)構(gòu)造函數(shù)中ServicePointManager(簡(jiǎn)稱SP),另外則在實(shí)例化HttpClient構(gòu)造函數(shù)中即HttpClientHandler(簡(jiǎn)稱HCH),那么這二者是否有使用上的限制呢?

在.NET Framework中,內(nèi)置的HttpClient建立在HttpWebRequest之上,因此可以使用SC來(lái)配置

在.NET Core中,通過(guò)SP配置證書(shū)信息僅影響HttpWebRequest,而對(duì)HttpClient無(wú)效,需通過(guò)HCH配置來(lái)達(dá)到相同目的

所以去除在靜態(tài)構(gòu)造函數(shù)中對(duì)忽略證書(shū)的配置,改為在HttpClientHandler中

var?client?=?new?HttpClient(new?HttpClientHandler {ServerCertificateCustomValidationCallback?=?(message,?cert,?chain,?error)?=>?true,SslProtocols?=?SslProtocols.Tls12 })

回到本文的話題,為什么會(huì)重置連接即主動(dòng)關(guān)閉連接呢?我們已分析過(guò),和上述配置30s超時(shí)沒(méi)有關(guān)系,主要有兩方面原因

翻開(kāi)并溫習(xí)《圖解HTTP》一書(shū),如果請(qǐng)求頻繁,最好建立持久連接,減少TCP連接的重復(fù)建立和斷開(kāi)所造成的額外開(kāi)銷(xiāo),從而減輕服務(wù)端負(fù)載即重用HTTP連接,也稱為Http keep-alive,持久連接的特點(diǎn)是,只要任意一方?jīng)]有明確提出斷開(kāi)連接,否則保持TCP連接狀態(tài)

配置keep-alive我們俗稱為保活機(jī)制,所以在默認(rèn)請(qǐng)求頭中添加如下一行

?//增加保活機(jī)制,表明連接為長(zhǎng)連接client.DefaultRequestHeaders.Connection.Add("keep-alive");

上述只是在報(bào)文頭中添加持久化連接標(biāo)識(shí),但不意味著就一定生效,因?yàn)槟J(rèn)是禁用持久化連接,所以為了保險(xiǎn)起見(jiàn),添加如下代碼

??//啟用保活機(jī)制(保持活動(dòng)超時(shí)設(shè)置為 2 小時(shí),并將保持活動(dòng)間隔設(shè)置為 1 秒。)ServicePointManager.SetTcpKeepAlive(true,?7200000,?1000);

有個(gè)讓我很疑惑的問(wèn)題,通過(guò)查看設(shè)置啟用持久化連接源碼得知,這樣設(shè)置意義在哪里?沒(méi)弄明白,源碼如下

public?static?void?SetTcpKeepAlive(bool?enabled,?int?keepAliveTime,?int?keepAliveInterval) {if?(enabled){if?(keepAliveTime?<=?0){throw?new?ArgumentOutOfRangeException(nameof(keepAliveTime));}if?(keepAliveInterval?<=?0){throw?new?ArgumentOutOfRangeException(nameof(keepAliveInterval));}} }

最關(guān)鍵的一點(diǎn)則是默認(rèn)持久化連接數(shù)為2,非持久化連接為4

????public?class?ServicePointManager{public?const?int?DefaultNonPersistentConnectionLimit?=?4;public?const?int?DefaultPersistentConnectionLimit?=?2;private?ServicePointManager()?{?}}

那么問(wèn)題是否就已很明了,項(xiàng)目中使用非持久化連接,即連接為4,未深究源碼具體細(xì)節(jié),大膽猜想一下,若連接大于4,是否會(huì)出現(xiàn)將此前連接主動(dòng)關(guān)閉,重建新的連接請(qǐng)求呢?

最終我們講原始代碼修改為如下形式

static?class?Program {static?HttpClient?httpClient?=?CreateHttpClient();static?Program(){//默認(rèn)連接數(shù)限制為2,增加連接數(shù)限制ServicePointManager.DefaultConnectionLimit?=?512;//啟用保活機(jī)制(保持活動(dòng)超時(shí)設(shè)置為 2 小時(shí),并將保持活動(dòng)間隔設(shè)置為 1 秒。)ServicePointManager.SetTcpKeepAlive(true,?7200000,?1000);}static?async?Task?Main(string[]?args){await?httpClient.PostAsync("",?new?StringContent(""));Console.WriteLine("Hello?World!");}static?HttpClient?CreateHttpClient(){var?client?=?new?HttpClient(new?HttpClientHandler{ServerCertificateCustomValidationCallback?=?(message,?cert,?chain,?error)?=>?true,SslProtocols?=?SslProtocols.Tls12}){Timeout?=?TimeSpan.FromSeconds(30)};client.DefaultRequestHeaders.Accept.Clear();//增加保活機(jī)制,表明連接為長(zhǎng)連接client.DefaultRequestHeaders.Connection.Add("keep-alive");client.DefaultRequestHeaders.Accept.Add(new?MediaTypeWithQualityHeaderValue("application/json"));client.DefaultRequestHeaders.Add("ContentType",?"application/json");return?client;} }

進(jìn)行如上設(shè)置后,通過(guò)一天觀察,再未出現(xiàn)相關(guān)異常,至此問(wèn)題解決告一段落,希望沒(méi)有后續(xù)......

強(qiáng)烈建議:利用HttpClient發(fā)送請(qǐng)求設(shè)置持久化連接和根據(jù)實(shí)際業(yè)務(wù)評(píng)估增加連接數(shù),而非默認(rèn)的持久化連接為2,非持久化連接為4,否則極易出現(xiàn)相關(guān)異常。

引發(fā)思考:利用HttpClientFactory創(chuàng)建HttpClient是否有默認(rèn)連接限制,據(jù)我所知,好像可以通過(guò)屬性MaxConnectionsPerServer來(lái)配置

若非常清楚默認(rèn)連接數(shù)限制,可能并算不上什么問(wèn)題,也不存在如此諸多分析,不過(guò)對(duì)于我而言,收獲的是在問(wèn)題排查過(guò)程中,對(duì)可能干擾信息的過(guò)濾、篩選、確認(rèn)以及對(duì)網(wǎng)絡(luò)協(xié)議進(jìn)一步的理解加深。

?????在.NET Core和.NET Framework中相關(guān)配置還是有些變化,最好是根據(jù)對(duì)應(yīng)版本在官網(wǎng)上確認(rèn)下

總結(jié)

以上是生活随笔為你收集整理的.NET Core HttpClient请求异常分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。