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

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()),会导致请求挂起。


修复方案

  1. 调整路由顺序:将精确匹配的/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) => {...});
  1. 完善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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:21:00