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

Express重构时多API调用报错:Can't set headers after they are sent.

Fixing "Can't set headers after they are sent" & Fetch Issues in Your Express Refactor

Hey Daniel, let's tackle this head-on—this error and your fetch JSON problem are tied together, and they're super common when juggling async operations in Express. Let's break down what's happening and fix it step by step.

First, Why You're Seeing That Header Error

The "Can't set headers after they are sent" message means Express has already finished sending a response to the client, but your code is still trying to modify the response (like updating res.locals or calling res.send() again).

In your case, this is almost certainly because your loop over the API URLs isn't waiting for all fetch requests to finish before sending the response. If you're using something like forEach with async/await, forEach doesn't pause for async operations—so your code probably sends the response early, then later when a fetch completes, it tries to update res.locals (or accidentally send another response) and hits the error.

Plus, Why You Can't Get JSON Data

Fetch doesn't automatically throw errors for HTTP status codes like 4xx or 5xx. If one of your API calls fails (e.g., 404, 500), you'll still get a response object, but calling response.json() on it might fail because the body isn't valid JSON. That unhandled error could also trigger unexpected behavior, including the header issue.

The Fix: Wait for All Async Operations & Handle Fetch Properly

Here's a revised approach that fixes both problems:

  1. Use Promise.all() to wait for all fetch requests to complete before touching the response.
  2. Properly validate fetch responses to catch errors early.
  3. Ensure you only send the response once, after all data is stored in res.locals.

Example Working Code

// Mark your route handler as async so we can use await
app.get('/your-endpoint', async (req, res, next) => {
  try {
    const apiUrls = ['https://api.example.com/1', 'https://api.example.com/2', /* ... your 9 URLs ... */];

    // Create an array of fetch promises (runs all requests in parallel)
    const fetchTasks = apiUrls.map(async (url) => {
      const response = await fetch(url);

      // Check if the response was successful first
      if (!response.ok) {
        throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
      }

      // Parse JSON only if the response is valid
      const data = await response.json();
      // Return the URL and data so we can map it to res.locals later
      return { url, data };
    });

    // Wait for all fetch tasks to finish
    const allResults = await Promise.all(fetchTasks);

    // Populate res.locals with all the fetched data
    allResults.forEach(({ url, data }) => {
      // You might want a cleaner key than the full URL—adjust as needed
      const key = url.split('/').pop(); // Example: uses the last segment of the URL as the key
      res.locals[key] = data;
    });

    // Now send the response ONCE, after all data is ready
    res.json({ 
      status: 'success',
      message: 'All API calls completed',
      storedData: res.locals
    });
  } catch (error) {
    // Pass any errors to Express's error-handling middleware
    next(error);
  }
});

Key Things to Remember

  • Never use forEach with async/await for operations you need to wait on—forEach doesn't respect async promises. Use map to create an array of promises, then Promise.all() to wait for all of them.
  • Always validate fetch responses with response.ok before parsing JSON. This prevents invalid JSON errors and lets you catch failed API calls early.
  • Only send the response once—make sure res.send(), res.json(), etc., are called after all async work is done, not inside loops or callbacks that might run multiple times.
  • Handle errors properly with try/catch and pass errors to next()—this keeps your code clean and lets Express handle error responses consistently.

This should resolve both the header error and your JSON parsing issue. Let me know if you need to adjust this for your specific use case!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:55:11