Node.js+PostgreSQL NBA统计应用错误处理方案问询
NBA统计应用错误处理问题
我正在开发一款NBA统计应用,已经把大量路由和数据库查询拆分到多个文件中,但对错误处理方式存在困惑。
相关代码
1. mutualScript.js中调用路由的函数
const getSeasonStatAvgLocal = async(stat, year, playerId, H_or_V) => { let url; if (H_or_V === 'home') { url = '/boxScoresTraditional/home/' + playerId + '/' + year; } else { url = '/boxScoresTraditional/visitor/' + playerId + '/' + year; } let gameDetailsArray = await getJsonResponse(url); let statTotal = await getSeasonTotalOfStat(stat.toLowerCase(), gameDetailsArray); //let gamesPlayed = await getGamesPlayedInSeason(gameDetailsArray); let gamesPlayed = gameDetailsArray.length; let statAverage = statTotal / gamesPlayed; return Number.parseFloat(statAverage).toFixed(2); }
2. mutualScript.js中的getJsonResponse函数
const getJsonResponse = async (url) => { console.log(url); const response = await fetch(url); try{ if (response.ok){ const jsonResponse = await response.json(); return jsonResponse; } } catch(err){ console.log(err); } }
3. boxScoresTraditionalRoutes.js路由文件
const express = require('express'); const router = express.Router(); const boxScoreTraditional = require('../services/boxscorestraditionalQueries') /** * @swagger * /boxScoresTraditional/home/{playerid}/{season}: * get: * parameters: * - in: path * name: playerid * schema: * type: string * required: true * description: String ID of the player who's box scores we are getting * - in: path * name: season * schema: * type: string * required: true * description: String season of the box scores we are getting * responses: * '200': * description: A successful response * */ router.get('/home/:playerid/:season', boxScoreTraditional.getBoxScoreTraditionalHome); router.get('/visitor/:playerid/:season', boxScoreTraditional.getBoxScoreTraditionalVisitor);
4. boxScoresTraditionalQueries.js数据库查询函数
const getBoxScoreTraditionalHome = (request, response) => { const {playerid, season} = request.params; let newSeason = JSON.stringify(season); let stringSeason = newSeason.replace(/"/g, ''); db.query(`SELECT * FROM "boxscorestraditional${stringSeason}" INNER JOIN "boxscoresummary${stringSeason}" ON "boxscorestraditional${stringSeason}".game_id = "boxscoresummary${stringSeason}".game_id WHERE player_id = $1 AND "boxscoresummary${stringSeason}".home_team_id = "boxscorestraditional${stringSeason}".team_id ORDER BY "boxscorestraditional${stringSeason}".id`, [playerid], (error, results) => { if (error) { throw error } response.status(200).json(results.rows) }) }
当前问题与需求
调用getBoxScoreTraditionalHome出现错误时,应用会崩溃,错误无法返回至前端getJsonResponse的catch块。我希望能在前端统一处理所有错误,或通过后端错误中间件处理。现咨询:如何在上述数据库查询的错误块中调用Express错误处理中间件?
解决方案
1. 修改数据库查询函数,传递错误到Express中间件
Express路由处理函数可以通过next(error)将错误交给全局错误中间件处理,替代直接throw error(回调里的throw会导致应用崩溃)。修改查询函数:
const getBoxScoreTraditionalHome = (request, response, next) => { // 添加next参数 const {playerid, season} = request.params; let newSeason = JSON.stringify(season); let stringSeason = newSeason.replace(/"/g, ''); db.query(`SELECT * FROM "boxscorestraditional${stringSeason}" INNER JOIN "boxscoresummary${stringSeason}" ON "boxscorestraditional${stringSeason}".game_id = "boxscoresummary${stringSeason}".game_id WHERE player_id = $1 AND "boxscoresummary${stringSeason}".home_team_id = "boxscorestraditional${stringSeason}".team_id ORDER BY "boxscorestraditional${stringSeason}".id`, [playerid], (error, results) => { if (error) { return next(error); // 传递错误给中间件,而非throw } response.status(200).json(results.rows) }) }
2. 配置全局错误处理中间件
在Express主文件(如app.js)中添加全局错误中间件,统一处理所有后端错误并返回规范响应:
// 全局错误处理中间件,必须包含4个参数(err, req, res, next) app.use((err, req, res, next) => { console.error('服务器错误详情:', err); // 返回统一格式的错误响应,生产环境可隐藏具体错误信息 res.status(500).json({ error: true, message: '服务器处理请求时出错', details: process.env.NODE_ENV === 'development' ? err.message : undefined }); });
3. 修复前端错误捕获逻辑
当前getJsonResponse仅处理了response.json()的异常,未覆盖后端返回错误状态码的情况,修改后确保捕获所有请求错误:
const getJsonResponse = async (url) => { console.log(url); try { const response = await fetch(url); if (!response.ok) { // 解析后端返回的错误信息,无则使用默认提示 const errorData = await response.json().catch(() => ({ message: '请求失败' })); throw new Error(`请求错误: ${response.status} - ${errorData.message || '未知错误'}`); } return await response.json(); } catch(err){ console.log(err); // 重新抛出错误,让上层调用者处理 throw err; } }
4. 前端调用层添加错误处理
在getSeasonStatAvgLocal中捕获错误,给用户返回友好提示或默认值:
const getSeasonStatAvgLocal = async(stat, year, playerId, H_or_V) => { try { let url; if (H_or_V === 'home') { url = '/boxScoresTraditional/home/' + playerId + '/' + year; } else { url = '/boxScoresTraditional/visitor/' + playerId + '/' + year; } let gameDetailsArray = await getJsonResponse(url); let statTotal = await getSeasonTotalOfStat(stat.toLowerCase(), gameDetailsArray); let gamesPlayed = gameDetailsArray.length; if (gamesPlayed === 0) { throw new Error('该赛季无有效比赛数据'); } let statAverage = statTotal / gamesPlayed; return Number.parseFloat(statAverage).toFixed(2); } catch (err) { console.error('计算场均数据出错:', err); // 返回友好提示或默认值 return 'N/A'; } }
额外优化:用async/await重构数据库查询
将数据库查询改为async/await形式,统一用try/catch捕获错误,避免回调嵌套:
const { promisify } = require('util'); // 包装db.query为支持promise的函数(如果原生不支持) const dbQuery = promisify(db.query); const getBoxScoreTraditionalHome = async (request, response, next) => { try { const {playerid, season} = request.params; let newSeason = JSON.stringify(season); let stringSeason = newSeason.replace(/"/g, ''); const results = await dbQuery(`SELECT * FROM "boxscorestraditional${stringSeason}" INNER JOIN "boxscoresummary${stringSeason}" ON "boxscorestraditional${stringSeason}".game_id = "boxscoresummary${stringSeason}".game_id WHERE player_id = $1 AND "boxscoresummary${stringSeason}".home_team_id = "boxscorestraditional${stringSeason}".team_id ORDER BY "boxscorestraditional${stringSeason}".id`, [playerid]); response.status(200).json(results.rows); } catch (error) { next(error); // 传递错误给全局中间件 } }
内容的提问来源于stack exchange,提问作者jack
相关产品推荐
相关产品推荐

