web超時(shí)配置總結(jié)

歡迎光臨我的博客拓跋的前端客棧,這個(gè)是原文地址。如果您發(fā)現(xiàn)我文章中存在錯(cuò)誤,請(qǐng)盡情向我吐槽,大家一起學(xué)習(xí)一起進(jìn)步φ(>ω<*)

引子


前段時(shí)間做項(xiàng)目時(shí),由于某個(gè)請(qǐng)求在后臺(tái)要進(jìn)行長(zhǎng)時(shí)間的腳本處理,頻頻超出系統(tǒng)默認(rèn)的超時(shí)時(shí)長(zhǎng),于是我就對(duì)超時(shí)時(shí)長(zhǎng)進(jìn)行了檢查。由于超時(shí)的時(shí)候請(qǐng)求報(bào)錯(cuò)的提示信息并不明確,為了修改這玩意兒也查了一堆資料,忙活了半天,終于把超時(shí)問(wèn)題解決了,在這里做個(gè)記錄。

我的項(xiàng)目用的是web前臺(tái)(這個(gè)無(wú)所謂用的什么框架,反正歸根結(jié)底是js)+nginx代理+Node.js后臺(tái)搭建的,我發(fā)現(xiàn)每一節(jié)都設(shè)了一道timeout超時(shí)的關(guān)卡,也就是說(shuō)有客戶端超時(shí)代理超時(shí)服務(wù)端超時(shí)三種情況。下面針對(duì)每種超時(shí),我將進(jìn)行分別講解。

timeout.jpg

客戶端超時(shí)


XMLHttpRequest的超時(shí)設(shè)置

講客戶端超時(shí),就要從XMLHttpRequest來(lái)談起。

XMLHttpRequest是一個(gè)API,它為客戶端提供了在客戶端和服務(wù)器之間傳輸數(shù)據(jù)的功能。它提供了一個(gè)通過(guò)URL來(lái)獲取數(shù)據(jù)的簡(jiǎn)單方式,并且不會(huì)使整個(gè)頁(yè)面刷新。這使得網(wǎng)頁(yè)只更新一部分頁(yè)面而不會(huì)打擾到用戶。XMLHttpRequest在AJAX中被大量使用。

XMLHttpRequest一開(kāi)始只是微軟瀏覽器提供的一個(gè)接口,后來(lái)各大瀏覽器紛紛效仿也提供了這個(gè)接口,再后來(lái)W3C對(duì)它進(jìn)行了標(biāo)準(zhǔn)化,提出了XMLHttpRequest標(biāo)準(zhǔn)。XMLHttpRequest標(biāo)準(zhǔn)又分為L(zhǎng)evel 1和Level 2。
XMLHttpRequest Level 1主要存在以下缺點(diǎn):

  • 受同源策略的限制,不能發(fā)送跨域請(qǐng)求;
  • 不能發(fā)送二進(jìn)制文件(如圖片、視頻、音頻等),只能發(fā)送純文本數(shù)據(jù);
  • 在發(fā)送和獲取數(shù)據(jù)的過(guò)程中,無(wú)法實(shí)時(shí)獲取進(jìn)度信息,只能判斷是否完成;

那么Level 2對(duì)Level 1 進(jìn)行了改進(jìn),XMLHttpRequest Level 2中新增了以下功能:

  • 可以發(fā)送跨域請(qǐng)求,在服務(wù)端允許的情況下;
  • 支持發(fā)送和接收二進(jìn)制數(shù)據(jù);
  • 新增formData對(duì)象,支持發(fā)送表單數(shù)據(jù);
  • 發(fā)送和獲取數(shù)據(jù)時(shí),可以獲取進(jìn)度信息;
  • 可以設(shè)置請(qǐng)求的超時(shí)時(shí)間;

在Level 2版本的XMLHttpRequest對(duì)象,增加了timeout屬性,可以設(shè)置HTTP請(qǐng)求的時(shí)限。

    xhr.timeout = 60*1000;
    xhr.ontimeout = function(event){
    alert('timeout!');
  }

在上述代碼中,請(qǐng)求超時(shí)時(shí)間被設(shè)為1分鐘(xhr.timeout的單位是毫秒),如果超過(guò)1分鐘的時(shí)限,則會(huì)自動(dòng)停止http請(qǐng)求;同時(shí),觸發(fā)ontimeout事件,彈出“timeout!”的提示框。

同時(shí)值得注意的一點(diǎn)是,超時(shí)時(shí)間的計(jì)算,是從調(diào)用xhr.send()開(kāi)始,至xhr.loadend觸發(fā)為止的這段時(shí)間。即時(shí)xhr.timeout的設(shè)置是在xhr.send()之后,timeout的計(jì)時(shí)起點(diǎn)仍為調(diào)用xhr.send()的時(shí)刻。

其他超時(shí)設(shè)置

其實(shí)會(huì)了XMLHttpRequest的超時(shí)設(shè)置,其他前端的框架啊、工具啊的超時(shí)設(shè)置都不再是問(wèn)題,這就有點(diǎn)萬(wàn)法歸宗的意思。因?yàn)槲覀兂S玫膉Query.ajax()方法實(shí)際上就是對(duì)瀏覽器提供的XMLHttpRequest對(duì)象的封裝。而又有很多其他框架或者工具的請(qǐng)求模塊是對(duì)jQuery.ajax()的封裝。說(shuō)到底,都是依賴(lài)的XMLHttpRequest對(duì)象。因此掌握了XMLHttpRequest,其他都很好學(xué)會(huì)。

依jQuery.ajax()的超時(shí)設(shè)置為例:

    $.ajax({
        url: "test.html",
        error: function(){
            // will fire when timeout is reached
        },
        success: function(){
            // do something
        },
        timeout: 60*1000 // sets timeout to 1 minute
    });

實(shí)在是簡(jiǎn)單,對(duì)不對(duì)?

代理超時(shí)


nginx的超時(shí)設(shè)置主要分3種:

  • proxy_connect_timeout
  • proxy_read_timeout
  • proxy_send_timeout

proxy_connect_timeout

語(yǔ)法: proxy_connect_timeout timeout_in_seconds
上下文: http, server, location
默認(rèn)值: 60s

proxy_connect_timeout是和后端建立連接的超時(shí)時(shí)間。需要記住的是,這個(gè)時(shí)間不能超過(guò)75秒。

這個(gè)不是等待后端返回頁(yè)面的時(shí)間,那是由proxy_read_timeout聲明的。如果你的upstream服務(wù)器起來(lái)了,但是掛起了(例如,沒(méi)有足夠的線程處理請(qǐng)求,所以把你的請(qǐng)求放到請(qǐng)求池里稍后處理),那么這個(gè)聲明是沒(méi)有用的,由于與upstream服務(wù)器的連接已經(jīng)建立了。

proxy_read_timeout

語(yǔ)法: proxy_read_timeout the_time
上下文: http, server, location
默認(rèn)值: 60s

proxy_read_timeout是從后端讀取數(shù)據(jù)的超時(shí)時(shí)間,兩次讀取操作的時(shí)間間隔如果大于這個(gè)值,和后端的連接會(huì)被關(guān)閉。如果一個(gè)請(qǐng)求時(shí)間時(shí)間非常大,要把這個(gè)值設(shè)大點(diǎn)。

proxy_send_timeout

語(yǔ)法: proxy_send_timeout time
上下文: http, server, location
默認(rèn)值: 60s

proxy_send_timeout是向后端寫(xiě)數(shù)據(jù)的超時(shí)時(shí)間,兩次寫(xiě)操作的時(shí)間間隔大于這個(gè)值,也就是過(guò)了這么長(zhǎng)時(shí)間后端還是沒(méi)有收到數(shù)據(jù),連接會(huì)被關(guān)閉。

服務(wù)端超時(shí)


Node.js做服務(wù)器時(shí),默認(rèn)的超時(shí)時(shí)長(zhǎng)為2分鐘。假設(shè)請(qǐng)求發(fā)送到服務(wù)端,在2分鐘內(nèi)沒(méi)有響應(yīng)返回給客戶端,客戶端的鏈接就會(huì)被重置。這個(gè)時(shí)長(zhǎng)的設(shè)置是很必要的,因?yàn)檫^(guò)長(zhǎng)的請(qǐng)求響應(yīng)會(huì)阻塞IO,造成極差的用戶體驗(yàn)。特別對(duì)于Node.js這種單線程應(yīng)用來(lái)說(shuō),影響可以說(shuō)是災(zāi)難性的,因此如何設(shè)置服務(wù)端的超時(shí)時(shí)間也是非常關(guān)鍵的。

服務(wù)端超時(shí)設(shè)置也不是一刀切的,總體來(lái)說(shuō),有一個(gè)總開(kāi)關(guān),還可以對(duì)每個(gè)服務(wù)端的請(qǐng)求或者響應(yīng)單獨(dú)設(shè)置超時(shí)時(shí)長(zhǎng)。

我們后面的代碼均以Node.js+Express搭建的后臺(tái)為例。

服務(wù)端超時(shí)總開(kāi)關(guān)

使用Node.js的http模塊啟動(dòng)服務(wù)器,并設(shè)置超時(shí)時(shí)長(zhǎng):

    const express = require('express');
    const config = require(./config);

    process.env.PORT = config.webport || 8888;

    let app = express();
    let server = app.listen(process.env.PORT);
    server.setTimeout(60*1000);
    server.on('timeout', function(){
        console.log('timeout!')
    })

server.setTimeout()是設(shè)置server的超時(shí)時(shí)間設(shè)置方法,單位是毫秒,一旦超過(guò)設(shè)置的超時(shí)時(shí)長(zhǎng),則觸發(fā)server對(duì)象的'timeout'事件,并傳入socket作為一個(gè)參數(shù)。

設(shè)置Express中間件超時(shí)時(shí)間

Express是一個(gè)路由和中間件Web框架,其自身只具有最低程度的功能:Express應(yīng)用程序基本上是一系列中間件函數(shù)調(diào)用。

中間件函數(shù)能夠訪問(wèn)請(qǐng)求對(duì)象 (req)、響應(yīng)對(duì)象 (res) 以及應(yīng)用程序的請(qǐng)求/響應(yīng)循環(huán)中的下一個(gè)中間件函數(shù)。下一個(gè)中間件函數(shù)通常由名為 next 的變量來(lái)表示。

中間件函數(shù)可以執(zhí)行以下任務(wù):

  • 執(zhí)行任何代碼。
  • 對(duì)請(qǐng)求和響應(yīng)對(duì)象進(jìn)行更改。
  • 結(jié)束請(qǐng)求/響應(yīng)循環(huán)。
  • 調(diào)用堆棧中的下一個(gè)中間件函數(shù)。

如果當(dāng)前中間件函數(shù)沒(méi)有結(jié)束請(qǐng)求/響應(yīng)循環(huán),那么它必須調(diào)用next(),以將控制權(quán)傳遞給下一個(gè)中間件函數(shù)。否則,請(qǐng)求將保持掛起狀態(tài)。

對(duì)于Express的中間件,我們可以在app.js里為每個(gè)路由及其處理程序函數(shù)的中間件設(shè)置請(qǐng)求的響應(yīng)和超時(shí)時(shí)間,

    app.get('/user/:id', function (req, res, next) {
        // 設(shè)置該中間件下所有HTTP請(qǐng)求的超時(shí)時(shí)間
        req.setTimeout(60*1000);
        // 設(shè)置該中間件下所有HTTP請(qǐng)求的服務(wù)器響應(yīng)超時(shí)時(shí)間
        res.setTimeout(60*1000);
        res.send('USER');
    });

Express不僅可以針對(duì)中間件設(shè)置超時(shí)時(shí)間,還可以針對(duì)某個(gè)具體的接口設(shè)置請(qǐng)求和響應(yīng)的超時(shí)時(shí)長(zhǎng):

    router.get('/user/:id', function (req, res, next) {
        // 設(shè)置該接口下所有HTTP請(qǐng)求的超時(shí)時(shí)間
        req.setTimeout(60*1000);
        // 設(shè)置該接口下所有HTTP請(qǐng)求的服務(wù)器響應(yīng)超時(shí)時(shí)間
        res.setTimeout(60*1000);
        res.send('USER');
    });

小結(jié)

全寫(xiě)完了以后,仔細(xì)想了想,發(fā)現(xiàn)還沒(méi)有寫(xiě)全,比如說(shuō)服務(wù)端也可以發(fā)請(qǐng)求,不管是用http.method還是用request模塊,都可以發(fā)請(qǐng)求。由于Node.js在很多項(xiàng)目中都是作為中間層,不管是向JAVA后臺(tái)請(qǐng)求數(shù)據(jù),還是用作解決客戶端跨域問(wèn)題的請(qǐng)求中轉(zhuǎn)層,發(fā)請(qǐng)求都是很常用的用法。但是只要讀者能耐心讀到這里,相信隨手網(wǎng)上搜一下就知道怎么寫(xiě)了,因此我這里就不再贅述了。

寫(xiě)這篇文章主要想分享一下我的感受,超時(shí)限制就像一道關(guān)卡,一個(gè)請(qǐng)求從客戶端到服務(wù)端,再?gòu)姆?wù)端返回客戶端的路上,要“過(guò)五關(guān)斬六將”。有的時(shí)候想要修改超時(shí)設(shè)置,可能不是簡(jiǎn)單修改某一處就能解決問(wèn)題的,這時(shí)候一定要仔細(xì)檢查,把這個(gè)系統(tǒng)理一遍,每一個(gè)地方的超時(shí)設(shè)置都看一看,才能解決問(wèn)題~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容

  • Ajax和XMLHttpRequest 我們通常將Ajax等同于XMLHttpRequest,但細(xì)究起來(lái)它們兩個(gè)是...
    changxiaonan閱讀 2,256評(píng)論 0 2
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,824評(píng)論 18 139
  • 看到標(biāo)題時(shí),有些同學(xué)可能會(huì)想:“我已經(jīng)用xhr成功地發(fā)過(guò)很多個(gè)Ajax請(qǐng)求了,對(duì)它的基本操作已經(jīng)算挺熟練了。” 我...
    前端渣渣閱讀 5,779評(píng)論 1 12
  • 本文詳細(xì)介紹了 XMLHttpRequest 相關(guān)知識(shí),涉及內(nèi)容: AJAX、XMLHTTP、XMLHttpReq...
    semlinker閱讀 13,707評(píng)論 2 18
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 11,071評(píng)論 6 13