Next.js服務端渲染超時導致生產(chǎn)事故的問題排查和解決辦法
前言
前幾天公司平臺首頁崩潰了 504 Time-out,這里記錄一下問題排查和解決的過程。

排查和解決
排查過程
- step 1:檢查測試環(huán)境、開發(fā)環(huán)境未出現(xiàn)問題;
- step 2:檢查生產(chǎn)環(huán)境流水線,沒有最新部署,排除前端新部署代碼影響;
- step 3:檢查生產(chǎn)環(huán)境其他頁面
/about-us頁面展示正常,但是部分接口報錯超時。猜測是因為生產(chǎn)環(huán)境接口超時導致首頁的服務端請求返回超時,導致首頁返回超時; - step 4:本地開發(fā)調(diào)用生產(chǎn)環(huán)境接口,將所有在
getServerSideProps中發(fā)起的請求全部注釋后,首頁可以正常加載。
問題定位
首頁開啟了SSR渲染,getServerSideProps中的請求使用了簡單的fetch請求,只對普通錯誤做了兜底,但沒有考慮到請求超時的問題,請求超時導致了頁面返回超時,首頁報了504錯誤。
解決方案
優(yōu)化方案
- 放棄使用
SSR渲染,全部采用客戶端請求渲染; - 修改現(xiàn)有
fetch,通過AbortController、setTimeout手動添加超時處理; - 將
getServerSideProps的請求方式從fetch遷移到axios,借助axios本身自帶的超時配置,添加接口超時處理。
方案比較
- 放棄
SSR不可取,因為客戶端并發(fā)請求返回順序的問題可能會導致首頁的入場動畫混亂,且失去了部分首屏性能優(yōu)化; - 修改
fetch方法,需要手寫大量代碼,且AbortController是在Node.js 14.17.0+開始支持,當然也可以不去放棄掉請求,可以通過setTimeout和Promise.race提前reject,不過需要因為是自行實現(xiàn),風險大。 axios是十分成熟的請求庫,且項目中已經(jīng)引入,通過axios為請求添加超時處理十分方便。
實際解決方案
將fetch遷移到axios,借助axios已有的超時處理配置解決當前問題,添加首頁對getServerSideProps中請求超時的兜底,服務端請求超時后,立即返回空數(shù)組。
首頁所有的數(shù)據(jù)消費組件繼續(xù)兜底,當從getServerSideProps中獲取的數(shù)據(jù)為空數(shù)組時,會在客戶端再發(fā)一次請求,嘗試從客戶端獲取數(shù)據(jù)。
import axios from 'axios';
const ssrAxios = axios.create({
timeout: 3000,
timeoutErrorMessage: 'Request timed out'
});
export default ssrAxios;
export const getServerSideProps = async () => {
const addr = process.env.API_ADDR;
// 使用 Promise.allSettled 獲取所有請求的結果
const [
list1Res,
// ... ,
list2Res,
] = await Promise.allSettled([
ssrAxios.get(`${addr}/api/list1`),
// ... ,
ssrAxios.get(`${addr}/api/list2`),
]);
// 處理每個請求的結果
const list1 = handleFetchResult(list1Res, 'list1');
// ... ;
const list2 = handleFetchResult(list2Res, 'list2');
return {
props: {
list1: list1 ?? [],
// ... ,
list2: list2 ?? []
},
};
};
// Helper function to handle fetch results
const handleFetchResult = (result: PromiseSettledResult<any>, key: string) => {
if (result.status === 'rejected') {
console.error(`Failed to fetch ${key}:`, result.reason);
return [];
}
const { data, success } = result.value.data;
if (!success) {
console.error(`Failed to fetch ${key}`);
return [];
}
switch (key) {
case 'list1':
return data?.result || [];
// ... ;
case 'list2':
return data?.result || [];
default:
return [];
}
};
問題探究
問題猜測
- 接口性能瓶頸:生產(chǎn)環(huán)境接口響應時間波動大,
SSR并發(fā)請求存在短板 - SSR 超時機制缺失:未設置合理的請求超時閾值,導致慢請求影響頁面的生成和響應
- 錯誤處理不完善:前端錯誤處理考慮不全面,未區(qū)分超時錯誤與常規(guī)錯誤,只做了無返回或返回錯誤的處理,沒有對請求超時做兜底。
驗證猜想
本地模擬接口返回超時,首頁會無法成功加載。添加超時處理兜底后,首頁其他內(nèi)容可以正常展示。
詢問deepseek后,得知Next.js的getServerSideProps沒有內(nèi)置超時處理機制,因此長時間運行的getServerSideProps可能導致頁面無法及時返回,甚至觸發(fā)部署平臺(如Vercel)的超時錯誤。
結論
首頁開啟了SSR渲染,Next.js 必須在完成getServerSideProps中的所有操作后才能生成頁面并返回給客戶端。 需要在得到所有需要的props后,才會返回整個頁面。因為生產(chǎn)環(huán)境某個接口請求超時,并且沒有正確處理,可能會導致整個getServerSideProps的執(zhí)行時間延長,超過服務器的響應時間限制,從而使得頁面無法及時返回,出現(xiàn)超時錯誤。
思考改進
思考
雖然是因為后端服務崩了,接口請求超時導致的問題,但是因為部分服務崩掉導致整個前端首頁無法成功加載,作為前端開發(fā)人員的我還是有很大責任的。開發(fā)時我在對可能出現(xiàn)的錯誤進行兜底時,需要盡可能地考慮全面。
改進
服務端請求優(yōu)化,錯誤處理添加對請求超時的處理。
① 首次訪問使用SSR獲取最新數(shù)據(jù);
② 當SSR超時時自動降級到 CSR版本 ;
③ 保持首屏加載性能的同時提升可用性。
以上就是Next.js服務端渲染超時導致生產(chǎn)事故的排查和解決辦法的詳細內(nèi)容,更多關于Next.js服務端渲染超時的資料請關注腳本之家其它相關文章!
相關文章
js/jquery解析json和數(shù)組格式的方法詳解
本篇文章主要是對js/jquery解析json和數(shù)組格式的方法進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01
JavaScript中的數(shù)組遍歷forEach()與map()方法以及兼容寫法介紹
下面小編就為大家?guī)硪黄狫avaScript中的數(shù)組遍歷forEach()與map()方法以及兼容寫法介紹。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-05-05
javascript addLoadEvent函數(shù)說明
網(wǎng)頁加載完整后會觸發(fā)一個onload事件,默認地一個事件只能和一個函數(shù)綁定。2010-01-01

