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

使用async/await实现查询等待时渲染页面的问题排查

ERR_HTTP_HEADERS_SENT错误解析及加载状态实现方案

错误根源

你这段代码的问题很明确:一个HTTP请求只能对应一次响应。你先调用await res.render('waiting.ejs'),这已经把完整的响应(包括响应头和页面内容)发给客户端了,之后又调用res.render('index.ejs'),试图再次发送响应,这就违反了HTTP协议规则,直接触发了Error [ERR_HTTP_HEADERS_SENT]错误。

正确实现思路

要实现“先显示加载动画,查询完成后展示结果页”的效果,不能靠后端两次渲染,得让前端和后端配合:

  1. 后端先返回包含加载动画的页面;
  2. 前端页面加载完成后,自动发起AJAX请求去查询数据库;
  3. 后端处理查询请求,返回数据;
  4. 前端拿到数据后,要么跳转到结果页,要么直接在当前页面替换内容。

代码示例

后端代码拆分

把原来的接口拆成两个:一个返回加载页面,一个处理数据查询:

// 返回带加载动画的页面
board: (req, res) => {
  res.render('waiting.ejs');
},

// 异步处理数据库查询并返回JSON数据
boardData: async (req, res) => {
  try {
    const result = await new Promise((resolve, reject) => {
      db2.query(queryboard.join(';'), (err, result) => {
        if (err) {
          console.log(`sql error ${queryboard}`);
          reject(err);
        }
        resolve(result);
      });
    });
    res.json({ success: true, data: result });
  } catch (err) {
    res.status(500).json({ success: false, error: '数据库查询失败' });
  }
}

前端waiting.ejs页面

在页面里放加载GIF,然后用JS发起请求:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>数据加载中</title>
  <style>
    .loading-container {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
    }
    .loading-gif {
      width: 60px;
      height: 60px;
    }
  </style>
</head>
<body>
  <div class="loading-container">
    <img class="loading-gif" src="/images/loading.gif" alt="加载中">
    <p>正在查询数据,请稍候...</p>
  </div>

  <script>
    // 页面加载完成后自动请求数据
    async function fetchData() {
      try {
        const response = await fetch('/boardData');
        const result = await response.json();
        
        if (result.success) {
          // 方式1:跳转到结果页,可通过URL参数传递数据
          window.location.href = `/boardResult?data=${encodeURIComponent(JSON.stringify(result.data))}`;
          
          // 方式2:直接在当前页面渲染结果(推荐,无跳转更流畅)
          // const pageResponse = await fetch('/boardResult', {
          //   method: 'POST',
          //   headers: { 'Content-Type': 'application/json' },
          //   body: JSON.stringify(result.data)
          // });
          // document.body.innerHTML = await pageResponse.text();
        } else {
          alert(`查询失败:${result.error}`);
        }
      } catch (err) {
        alert('网络请求失败,请刷新重试');
      }
    }

    window.onload = fetchData;
  </script>
</body>
</html>

额外说明

  • 如果选择跳转方式,需要再写一个boardResult接口来接收数据并渲染index.ejs;
  • 也可以用WebSocket实现实时推送,但AJAX是最轻量化的方案,适合你的场景;
  • 记得处理异常情况,比如数据库查询失败、网络超时等,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:50:32