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

Firebase路由返回错误状态后仍执行后续逻辑引发响应错误

Fixing [ERR_HTTP_HEADERS_SENT] in Firebase Comment Function

Hey there, let's break down why your code is hitting that frustrating ERR_HTTP_HEADERS_SENT error and how to fix it!

The Root Cause

The problem lies in how your Promise chain handles the "scream not found" scenario. When you return res.status(404).json({ error: 'Scream not found' }) in the first .then() callback, you're sending a response—but you're also returning an Express Response object, not a rejected Promise.

Promise chains treat any non-rejected value as a success, so the next .then() callbacks (adding the comment and sending another response) still run. This means you're sending a 404 response first, then trying to send a second response with the new comment—hence the error about setting headers after a response has already been sent.

Solution 1: Use Async/Await (Cleanest Approach)

Async/await makes control flow linear and easier to follow, which avoids this kind of Promise chain misstep. Here's how to refactor your code:

exports.commentOnScream = async (req, res) => {
  // Validate comment body first
  if (req.body.body.trim() === '') {
    return res.status(400).json({ comment: 'Must not be empty' });
  }

  const newComment = {
    body: req.body.body,
    createdAt: new Date().toISOString(),
    screamId: req.params.screamId,
    userHandle: req.user.handle,
    userImage: req.user.imageUrl
  };

  try {
    // Fetch the scream document
    const screamDoc = await db.doc(`/screams/${req.params.screamId}`).get();
    
    // If scream doesn't exist, return 404 and exit immediately
    if (!screamDoc.exists) {
      return res.status(404).json({ error: 'Scream not found' });
    }

    // Update comment count
    await screamDoc.ref.update({ commentCount: screamDoc.data().commentCount + 1 });
    // Add new comment to collection
    await db.collection('comments').add(newComment);
    
    // Return success response
    return res.json(newComment);
  } catch (err) {
    console.log(err);
    return res.status(500).json({ error: 'Something went wrong' });
  }
};

With async/await, when we hit return res.status(404)..., the function exits right away—none of the subsequent code (updating counts, adding comments) runs, so we only send one response.

Solution 2: Fix the Promise Chain

If you prefer sticking with .then() syntax, you need to interrupt the chain when the scream isn't found. Throw a custom error to jump directly to the .catch() block instead of returning a response:

exports.commentOnScream = (req, res) => {
  if (req.body.body.trim() === '') return res.status(400).json({ comment: 'Must not be empty' });
  const newComment = {
    body: req.body.body,
    createdAt: new Date().toISOString(),
    screamId: req.params.screamId,
    userHandle: req.user.handle,
    userImage: req.user.imageUrl
  };
  db.doc(`/screams/${req.params.screamId}`)
    .get()
    .then((doc) => {
      if (!doc.exists) {
        // Throw an error to stop the chain and trigger catch
        throw new Error('Scream not found');
      } else {
        return doc.ref.update({ commentCount: doc.data().commentCount + 1 });
      }
    })
    .then(() => {
      return db.collection('comments').add(newComment);
    })
    .then(() => {
      return res.json(newComment);
    })
    .catch((err) => {
      console.log(err);
      // Check for our custom error to return the right status code
      if (err.message === 'Scream not found') {
        return res.status(404).json({ error: err.message });
      }
      return res.status(500).json({ error: 'Something went wrong' });
    });
};

Throwing an error skips all remaining .then() callbacks and sends us straight to .catch(), where we can handle the 404 case without conflicting responses.

内容的提问来源于stack exchange,提问作者code.cycling

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:35:42