使用async仍遇await只能在async函数内使用错误及API调用问题排查
Let's tackle your two main problems step by step: the await is only valid in async functions error, and the failed external API calls with node-fetch/request.
1. Fixing the "await can only be used in async function" Error
The core issue here is scope mismatch: you marked the top-level router.post callback as async, but the nested successFunc callback inside db.getref is a regular synchronous function. When you try to use await fetch(...) inside that nested callback, it's not wrapped in an async context—hence the error.
Solution: Convert nested callbacks to async functions
Update the nested callbacks to be async so await works as expected, and add critical error handling:
const notify = router.post('/', async (req, res) => { console.log(req.body); const CLIENT_SECRET = process.env.PAYMENT_TEST_SECRET_KEY; let postData = { oid: req.body.orderId, amt: req.body.orderAmount, rsn: req.body.txMsg, tt: req.body.txTime } let signData = req.body.orderId + req.body.orderAmount + req.body.referenceId + req.body.txStatus + req.body.paymentMode + req.body.txMsg + req.body.txTime; let sdata = util.computeSign(signData); if (sdata == req.body.signature) { let data = { sts: 'Inprogress' }; // Convert db.getref's success callback to async db.getref(postData.oid, 'txn', async (successFunc) => { if (successFunc) { const txnid = successFunc.id; const appId = successFunc.appid; db.updateById( txnid, data, 'txn', async (success) => { // Mark this callback as async too if (success) { let payload = { txnId: txnid }; let PAYOUT_URI = 'https://ap.moneyorder.ws/api/v1/payout/test' let Token = 'ceobrtoen' let options = { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json', // Critical for JSON payloads appid: appId, token: Token } } try { let response = await fetch(PAYOUT_URI, options); // Catch HTTP errors (4xx/5xx status codes) if (!response.ok) { throw new Error(`API request failed: ${response.status} ${response.statusText}`); } let tokenres = await response.json(); if (tokenres && tokenres.status === 'SUCCESS') { let updateObj = { sts: 'Success' }; db.updateById( txnid, updateObj, 'txn', (success) => { if (success) { console.log("payout updated") // Fixed typo: cosole → console } else { res.status(status.HTTPS.SERVER_ERROR).json({ data: null, msg: 'Something went wrong at our end.', success: false }) } }, (err) => { res.status(status.HTTPS.SERVER_ERROR).json({ data: null, msg: 'Something went wrong at our end.', success: false }) } ) } else { res.status(status.HTTPS.SERVER_ERROR).json({ data: null, msg: "Payout API returned non-success status", success: false }) } } catch (error) { console.error('Fetch error details:', error); // Log full error for debugging res.status(status.HTTPS.SERVER_ERROR).json({ data: null, msg: 'Something went wrong at our end.', success: false }) } } }, (err) => { res.status(status.HTTPS.BAD_REQUEST).json({ success: false, msg: 'error 404', data: null }) } ) } else { res.status(status.HTTPS.BAD_REQUEST).json({ success: false, msg: "empty response" }) } }) } else { console.log('Signature mismatch details:'); console.log('Generated sign data:', signData); console.log('Computed signature:', sdata); console.log('Received signature:', req.body.signature); // Send a response to avoid client timeout res.status(status.HTTPS.UNAUTHORIZED).json({ success: false, msg: "Invalid signature" }) } })
Key fixes here:
- Marked nested callbacks as
asyncto enableawaitusage - Added
Content-Type: application/jsonheader (required for sending JSON payloads to APIs) - Fixed the
cosole.logtypo - Added HTTP error checking for
node-fetch(it doesn't throw errors for 4xx/5xx status codes by default) - Added detailed error logging to debug API issues
- Added a response for signature mismatch to prevent client hangs
2. Troubleshooting External API Call Failures
Whether you use node-fetch or request, these common fixes will resolve most API call issues:
Critical Checks for Both Libraries:
- Missing Content-Type Header: Always include
Content-Type: application/jsonwhen sending JSON payloads—APIs often reject requests without this. - Invalid URL: Double-check the payout API URL (your commented
requestcode had a missing closing quote:'https://ap.moneyorder.ws/api/v1/payout/test→ fix this if you revert torequest). - Credential Validation: Verify that
TokenandappIdare correct. Temporarily log these values to confirm they're being passed properly. - Payload Structure: Cross-reference the API documentation to ensure your
txnIdpayload matches the expected format.
Corrected request Module Example:
If you prefer using request, here's a robust version with proper error handling:
let payload = { txnId: txnid }; let Token = 'ceobrtoen'; const PAYOUT_URI = 'https://ap.moneyorder.ws/api/v1/payout/test'; // Fixed quote let options = { method: 'POST', url: PAYOUT_URI, body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json', // Add this header appid: appId, token: Token } } request(options, (err, response, body) => { if (err) { console.error('Request network error:', err); res.status(status.HTTPS.SERVER_ERROR).json({ msg: 'Something went wrong.' }) return; } // Catch HTTP errors if (response.statusCode >= 400) { console.error('API error response:', body); res.status(response.statusCode).json({ msg: 'Payout API error', error: body }) return; } try { let data = JSON.parse(body); console.log('Payout API response:', data); if (data && data.status === 'SUCCESS') { // Update txn record logic here } else { res.status(status.HTTPS.SERVER_ERROR).json({ data: null, msg: "Payout API failed", success: false }) } } catch (parseErr) { console.error('Failed to parse API response:', parseErr); res.status(status.HTTPS.SERVER_ERROR).json({ msg: 'Invalid response from payout API' }) } })
Debugging Tips:
- Test the payout API directly with Postman or curl using your credentials and payload. This confirms if the issue is with your code or the API itself.
- Log the full request options (URL, headers, body) before sending to verify formatting.
- Check the API's documentation for any additional required headers or fields you might be missing.
内容的提问来源于stack exchange,提问作者Prateek Pareek

