Express路由/api/budget/search未执行返回空值问题求助
Express路由匹配异常排查与修复
问题现象
两段逻辑完全一致的Express路由,表现截然不同:
/api/budget/search路由:认证通过后返回[],服务器端未打印日志;Postman测试返回200 OK,但无有效数据/api/users/search路由:完全相同的代码,可正常返回预期查询结果
客户端调用代码
前端请求方法(Vue)
async search(){ const query = this.$refs.searchInput.value; console.log(query); const addressToFetch = "/api/budget/search?q=" + query; await fetch(addressToFetch) .then((response) => response.json()) .then((response) => { console.log(response); }); }
输入框HTML结构
<div class="input-group row text-right"> <div class="col"> <input type="text" id="searchInput" name="search" placeholder="Search" ref="searchInput" /> <button type="button" class="btn btn-primary btn-search btn-filter" @click="search" > <i class="fa fa-search" aria-hidden="true"></i> </button> <button type="button" class="btn btn-danger" v-if="filteredResults" @click="getExpenses" > Undo </button> </div> </div>
服务器端路由代码
异常路由(/api/budget/search)
app.get("/api/budget/search", verify, async (req, res) => { console.log(req.query.q); const users = await db .collection("users") .find({ username: { $regex: req.query.q } }) .toArray(); users.forEach((user) => { delete user.password; }); res.json(users); });
正常测试路由(/api/users/search)
app.get("/api/users/search", verify, async (req, res) => { console.log(req.query.q); const users = await db .collection("users") .find({ username: { $regex: req.query.q } }) .toArray(); users.forEach((user) => { delete user.password; }); res.json(users); });
完整路由定义
const express = require("express"); const fs = require("fs/promises"); const session = require("express-session"); const { MongoClient } = require("mongodb"); const exp = require("constants"); const uri = "mongodb://mongohost"; const app = express(); const client = new MongoClient(uri); let db = null; app.use(express.static(`${__dirname}/public`)); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use( session({ secret: "segreto", resave: false, }) ); function verify(req, res, next) { if (req.session.user) { next(); } else { res.status(403); } } app.post("/api/auth/signup", async (req, res) => {}); app.post("/api/auth/signin", async (req, res) => {...}); app.get("/api/budget/whoami", verify, (req, res) => {...}); app.get("/api/budget", verify, async (req, res) => {...}); app.get("/api/budget/:year", verify, async (req, res) => {...}); app.get("/api/budget/:year/:month", verify, async (req, res) => {...}); app.get("/api/budget/:year/:month/:id", verify, async (req, res) => {...}); app.post("/api/budget/:year/:month", verify, async (req, res) => {...}); app.put("/api/budget/:year/:month/:id", verify, async (req, res) => {...}); app.delete("/api/budget/:year/:month/:id", verify, async (req, res) => {...}); app.get("/api/balance", verify, async (req, res) => {...}); app.get("/api/balance/:id", verify, async (req, res) => {...}); app.get("/api/budget/search", verify, async (req, res) => {...}); app.get("/api/users/search", verify, async (req, res) => {...}); app.listen(3000, async () => { await client.connect(); db = client.db("balanceApp"); });
问题根源
Express的路由匹配是按定义顺序执行的,当请求/api/budget/search时,会先匹配到前面定义的/api/budget/:year路由——Express会把search识别为:year参数的取值,直接进入该路由的处理逻辑,导致真正的/api/budget/search路由永远不会被触发。
而/api/users/search没有类似的前置参数路由,因此能正常匹配执行。
另外,verify中间件存在小问题:认证失败时仅设置了403状态码,但未结束响应(如res.send()或res.end()),会导致请求挂起。
修复方案
- 调整路由顺序:将精确匹配的
/api/budget/search路由,移到所有带参数的/api/budget/xxx路由之前,确保精确路由优先匹配:
// 先定义精确匹配的search路由 app.get("/api/budget/search", verify, async (req, res) => {...}); // 再定义带参数的路由 app.get("/api/budget/:year", verify, async (req, res) => {...}); app.get("/api/budget/:year/:month", verify, async (req, res) => {...}); app.get("/api/budget/:year/:month/:id", verify, async (req, res) => {...});
- 完善verify中间件:认证失败时结束响应,避免请求挂起:
function verify(req, res, next) { if (req.session.user) { next(); } else { res.status(403).send("Authentication required"); // 或res.end() } }
内容的提问来源于stack exchange,提问作者Eminent Emperor Penguin
相关产品推荐
相关产品推荐

