Next.js服务端渲染超时导致生产事故的问题排查和解决办法

 更新时间:2025年03月05日 10:29:34   作者:HyaCinth  
Next.js是一个基于React的开源框架,用于构建服务端渲染(SSR)的Web应用程序,它简化了许多复杂的配置,让开发者可以专注于编写应用逻辑而不是基础设施,前几天公司平台首页崩溃了 504 Time-out,这里记录一下问题排查和解决的过程,需要的朋友可以参考下

前言

前几天公司平台首页崩溃了 504 Time-out,这里记录一下问题排查和解决的过程。

排查和解决

排查过程

  • step 1:检查测试环境、开发环境未出现问题;
  • step 2:检查生产环境流水线,没有最新部署,排除前端新部署代码影响;
  • step 3:检查生产环境其他页面/about-us页面展示正常,但是部分接口报错超时。猜测是因为生产环境接口超时导致首页的服务端请求返回超时,导致首页返回超时;
  • step 4:本地开发调用生产环境接口,将所有在getServerSideProps中发起的请求全部注释后,首页可以正常加载。

问题定位

首页开启了SSR渲染,getServerSideProps中的请求使用了简单的fetch请求,只对普通错误做了兜底,但没有考虑到请求超时的问题,请求超时导致了页面返回超时,首页报了504错误。

解决方案

优化方案

  • 放弃使用SSR渲染,全部采用客户端请求渲染;
  • 修改现有fetch,通过AbortControllersetTimeout手动添加超时处理;
  • getServerSideProps的请求方式从fetch迁移到axios,借助axios本身自带的超时配置,添加接口超时处理。

方案比较

  • 放弃SSR不可取,因为客户端并发请求返回顺序的问题可能会导致首页的入场动画混乱,且失去了部分首屏性能优化;
  • 修改fetch方法,需要手写大量代码,且AbortController是在Node.js 14.17.0+开始支持,当然也可以不去放弃掉请求,可以通过setTimeoutPromise.race提前reject,不过需要因为是自行实现,风险大。
  • axios是十分成熟的请求库,且项目中已经引入,通过axios为请求添加超时处理十分方便。

实际解决方案

fetch迁移到axios,借助axios已有的超时处理配置解决当前问题,添加首页对getServerSideProps中请求超时的兜底,服务端请求超时后,立即返回空数组。

首页所有的数据消费组件继续兜底,当从getServerSideProps中获取的数据为空数组时,会在客户端再发一次请求,尝试从客户端获取数据。

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 [];
  }
};

问题探究

问题猜测

  • 接口性能瓶颈:生产环境接口响应时间波动大,SSR并发请求存在短板
  • SSR 超时机制缺失:未设置合理的请求超时阈值,导致慢请求影响页面的生成和响应
  • 错误处理不完善:前端错误处理考虑不全面,未区分超时错误与常规错误,只做了无返回或返回错误的处理,没有对请求超时做兜底。

验证猜想

本地模拟接口返回超时,首页会无法成功加载。添加超时处理兜底后,首页其他内容可以正常展示。

询问deepseek后,得知Next.jsgetServerSideProps没有内置超时处理机制,因此长时间运行的getServerSideProps可能导致页面无法及时返回,甚至触发部署平台(如Vercel)的超时错误。

结论

首页开启了SSR渲染,Next.js 必须在完成getServerSideProps中的所有操作后才能生成页面并返回给客户端。 需要在得到所有需要的props后,才会返回整个页面。因为生产环境某个接口请求超时,并且没有正确处理,可能会导致整个getServerSideProps的执行时间延长,超过服务器的响应时间限制,从而使得页面无法及时返回,出现超时错误。

思考改进

思考

虽然是因为后端服务崩了,接口请求超时导致的问题,但是因为部分服务崩掉导致整个前端首页无法成功加载,作为前端开发人员的我还是有很大责任的。开发时我在对可能出现的错误进行兜底时,需要尽可能地考虑全面。

改进

服务端请求优化,错误处理添加对请求超时的处理。

① 首次访问使用SSR获取最新数据;

② 当SSR超时时自动降级到 CSR版本 ;

③ 保持首屏加载性能的同时提升可用性。

以上就是Next.js服务端渲染超时导致生产事故的排查和解决办法的详细内容,更多关于Next.js服务端渲染超时的资料请关注脚本之家其它相关文章!

相关文章

  • 原生JavaScript实现todolist功能

    原生JavaScript实现todolist功能

    本篇文章给大家介绍了通过原生JavaScript实现todolist功能相关知识点,对此有需要的朋友可以学习下。
    2018-03-03
  • JS对象复制(深拷贝和浅拷贝)

    JS对象复制(深拷贝和浅拷贝)

    这篇文章主要介绍了JS对象复制(深拷贝和浅拷贝),并附有详细代码,感兴趣的小伙伴们,可以参考下
    2021-04-04
  • 前端滚动锚点三个常用方案(点击后页面滚动到指定位置)

    前端滚动锚点三个常用方案(点击后页面滚动到指定位置)

    这篇文章主要给大家介绍了关于前端滚动锚点的三个常用方案,实现的效果就是点击后页面滚动到指定位置,三种方法分别是scrollIntoView、scrollTo和scrollBy,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-01-01
  • 微信小程序 弹窗输入组件的实现解析

    微信小程序 弹窗输入组件的实现解析

    这篇文章主要介绍了微信小程序 弹窗输入组件的实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • js中substr,substring,indexOf,lastIndexOf,split,replace的用法详解

    js中substr,substring,indexOf,lastIndexOf,split,replace的用法详解

    这篇文章主要介绍了js中substr,substring,indexOf,lastIndexOf,split,replace的用法详解的相关资料,需要的朋友可以参考下
    2015-11-11
  • 理解javascript中的Function.prototype.bind的方法

    理解javascript中的Function.prototype.bind的方法

    这篇文章主要介绍了理解javascript中的Function.prototype.bind的方法,具有一定参考价值,有兴趣的可以了解一下。
    2017-02-02
  • 基于Express框架使用POST传递Form数据

    基于Express框架使用POST传递Form数据

    这篇文章主要为大家详细介绍了基于Express框架使用POST传递Form数据,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • ES6中module模块化开发实例浅析

    ES6中module模块化开发实例浅析

    这篇文章主要介绍了ES6中module模块化开发,结合实例形式分析了ES6中模块化开发的相关功能、使用方法与相关注意事项,需要的朋友可以参考下
    2017-04-04
  • jQuery实现文字自动横移

    jQuery实现文字自动横移

    本文详细介绍了通过jquery尺寸相关函数实现文字自动横移的方法。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • php的派发机制实现方法

    php的派发机制实现方法

    PHP是一种动态类型的编程语言,它支持面向对象编程,在PHP中,派发指在运行时确定要调用的方法或函数的过程,派发机制允许根据实际对象的类型来选择要执行的方法,这种灵活性使得PHP可以实现多态性,本文将给大家介绍php的派发机制是怎么实现的,需要的朋友可以参考下
    2023-10-10

最新评论