You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Fetch请求时浏览器无法显示EJS渲染的错误页面

问题根源

核心原因是Fetch属于异步AJAX请求,和普通表单提交的页面级请求逻辑完全不同:

  • 普通GET/POST表单提交时,浏览器直接发起页面请求,后端返回的任何响应(包括错误页面)都会被浏览器自动渲染为当前页面
  • 而Fetch是通过JS发起的异步请求,浏览器只会在JS上下文里接收响应内容,不会自动替换当前页面,所以你能在DevTools看到响应,但页面不会发生变化
解决方案

可以从前端或后端两个方向调整,让错误处理逻辑适配AJAX场景:

方案1:前端主动处理错误响应

在Fetch请求中,判断响应状态码,若为错误码(4xx/5xx),则手动处理错误页面的渲染:

fetch('/your-put-endpoint', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    // 可选:添加自定义头让后端识别AJAX请求
    'X-Requested-With': 'XMLHttpRequest'
  },
  body: JSON.stringify(yourFormData)
})
.then(response => {
  if (!response.ok) {
    // 读取后端返回的错误页面HTML
    return response.text().then(html => {
      // 替换当前页面内容为错误页面
      document.body.innerHTML = html;
      // 或者如果后端有独立错误路由,直接跳转:
      // window.location.href = '/error-page';
    });
  }
  // 正常情况的处理,比如跳转成功页面
  window.location.href = '/success';
})
.catch(error => {
  // 处理网络层面的错误
  console.error('请求失败:', error);
});

方案2:后端区分请求类型,返回对应格式响应

修改全局错误中间件,根据请求头判断是否为AJAX请求,返回JSON或HTML错误:

// Express全局错误中间件
app.use((err, req, res, next) => {
  // 判断是否为AJAX请求:检查自定义头或Accept头
  const isAjax = req.headers['x-requested-with'] === 'XMLHttpRequest' || 
                 req.headers.accept.includes('application/json');

  if (isAjax) {
    // 给AJAX请求返回JSON错误
    res.status(err.statusCode || 500).json({
      message: err.message,
      error: process.env.NODE_ENV === 'development' ? err.stack : {}
    });
  } else {
    // 普通请求继续渲染EJS错误页面
    res.status(err.statusCode || 500).render('error', { error: err });
  }
});

这种情况下,前端Fetch收到JSON错误后,可以选择弹出提示、渲染自定义错误组件,或者跳转到错误页面。

关键细节补充
  • 不要忽略Fetch的response.ok判断:Fetch只有在网络彻底失败时才会进入catch,后端返回的4xx/5xx状态码会被视为“成功的响应”,需要手动判断response.ok(状态码200-299为true)
  • 确保后端错误中间件正确设置了statusCode:比如JOI校验错误时,要给错误对象添加statusCode = 400,数据库错误设为500,这样前端才能准确识别错误类型

内容的提问来源于stack exchange,提问作者Harley Frey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:36:13