如何在Axios调用中正确抛出追加AppB错误的异常并避免超时?
Fixing Axios Catch Error Propagation with Stack Traces in Express
Let's break down what's causing your issues and fix them step by step:
What's Wrong With Your Current Code?
- Unsent Successful Response: In your
thenblock, you're just returningdata.datainstead of sending it to the client withres.send(). This means even successful calls will timeout because the client never gets a response. - Uncaptured Async Error: When you
throw ein thecatchblock, you're rejecting the Promise returned by the route handler. Older Express versions don't automatically handle rejected Promises from route handlers, leading to theUnhandledPromiseRejectionWarning. - Broken Stack Trace Handling: You're creating a string with the combined stack trace but never assigning it back to
e.stack—so your new error doesn't actually include the AppB error details.
Step-by-Step Fix
1. Update AppB to Return Structured Errors
First, make sure AppB sends a JSON-formatted error with both message and stack trace, so AppA can parse it easily:
// AppB route api.get('/', (req, res) => { const err = new Error('B'); res.status(500).json({ message: err.message, stack: err.stack }); }); // Add Express error-handling middleware to AppB (to catch all errors) api.use((err, req, res, next) => { res.status(500).json({ message: err.message, stack: err.stack }); });
2. Fix AppA's Route Handler
We'll use async/await to make async error handling cleaner (Express will automatically pass async errors to your error middleware):
// AppA route (using async/await) api.get('/', async (req, res, next) => { try { // Fetch data from AppB const axiosResponse = await axios({ method: "GET", url: "http://localhost:3060/api/" }); // Send successful response to client res.send(axiosResponse.data); } catch (err) { // Extract AppB's error from the axios response const appBError = err.response?.data || { message: 'Unknown AppB error' }; // Create new error with custom message const wrappedError = new Error(`Rethrowing the "${appBError.message}" error FROM A`); // Merge stack traces: keep our new error's top 2 lines, then append AppB's error details if (wrappedError.stack) { wrappedError.stack = [ // Keep the first two lines of our new error (message + immediate stack frame) ...wrappedError.stack.split('\n').slice(0, 2), '--- AppB Error Details ---', appBError.message, ...(appBError.stack ? appBError.stack.split('\n') : []) ].join('\n'); } // Throw the wrapped error—Express will pass it to your error middleware throw wrappedError; } });
3. Add Error-Handling Middleware to AppA
This ensures all errors (including our wrapped one) are sent to the client properly instead of timing out:
// AppA error-handling middleware (place this after all routes) api.use((err, req, res, next) => { console.error('Full error stack:', err.stack); res.status(500).json({ message: err.message, stack: err.stack }); });
Alternative: Without Async/Await
If you prefer to keep the Promise chain, replace throw e with next(e) to manually pass the error to Express's middleware:
api.get('/', (req, res, next) => { return axios({ method: "GET", url: "http://localhost:3060/api/" }) .then((axiosResponse) => { res.send(axiosResponse.data); }) .catch((err) => { const appBError = err.response?.data || { message: 'Unknown AppB error' }; const wrappedError = new Error(`Rethrowing the "${appBError.message}" error FROM A`); if (wrappedError.stack) { wrappedError.stack = wrappedError.stack.split('\n').slice(0,2).join('\n') + '\n--- AppB Error Details ---\n' + appBError.message + (appBError.stack ? '\n' + appBError.stack : ''); } // Pass error to Express middleware next(wrappedError); }); });
What This Fixes
- No more
UnhandledPromiseRejectionWarningbecause errors are properly captured by Express. - Clients get a timely response (no more timeouts) whether the call succeeds or fails.
- The returned error includes both AppA's context and AppB's full error message + stack trace.
内容的提问来源于stack exchange,提问作者twcardenas
相关产品推荐
相关产品推荐

