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

Express.js跨路由共享变量方案及全局变量并发风险咨询

Express跨路由共享请求变量的最佳实践

我希望在一个Express.js路由中获取变量,并在另一个路由中使用。请问最佳方案是否为使用中间件?若是,该如何实现?另外,若在服务端初始位置声明全局变量,在同时处理多用户/请求时(对应React Native应用,非浏览器)是否会引发异常行为?

用户提供的原始代码:

const { Station } = require("../models/station");
const express = require("express");
const router = express.Router();
var deviceId;
var directionNumber;
var metroNumberChoice;
router.post("/postUserDirectionAndLineNumberAndDeviceId", async (req, res) => {
  try {
    directionNumber = req.body.direction;
    deviceId = req.body.deviceId;
    metroNumberChoice = req.body.metroNumberChoice;
    res.status(200).json({ message: "User direction received successfully" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
});
router.post("/getlocation", (req, res) => {
  try {
    console.log("deviceId", deviceId);
    const findMetro = async () => { 
      console.log(
        "directionNumber:",
        directionNumber,
        "metroNumberChoice:",
        metroNumberChoice,
        "deviceId:",
        deviceId
      );
       
  } catch (error) {
    console.log(error);
  }
});

一、全局变量的问题:绝对会引发异常行为

直接在路由文件顶部声明全局变量(如deviceId、directionNumber)是严重错误的做法:

  • Express基于单线程事件循环模型,所有请求共享同一份内存空间。当多个用户/请求并发处理时,后一个请求会直接覆盖全局变量的值,导致前一个请求拿到完全错误的数据。
  • 举个例子:用户A提交deviceId=123后,用户B紧接着提交deviceId=456,当用户A触发/getlocation请求时,拿到的会是用户B的456,完全打乱业务逻辑。

二、最佳方案:请求对象(req)+ 中间件

中间件是Express处理请求生命周期的核心机制,用来在路由间共享请求级别的变量非常合适——每个请求都有独立的req对象,不会互相干扰。

实现方式分两种场景:

场景1:两个路由属于同一次请求链

如果/postUserDirectionAndLineNumberAndDeviceId和/getlocation是同一次请求流程中的前后步骤,可直接用中间件把变量挂载到req上:

const { Station } = require("../models/station");
const express = require("express");
const router = express.Router();

// 中间件:解析并存储用户地铁信息到req对象
const attachMetroInfo = (req, res, next) => {
  try {
    req.metroInfo = {
      directionNumber: req.body.direction,
      deviceId: req.body.deviceId,
      metroNumberChoice: req.body.metroNumberChoice
    };
    next(); // 传递到下一个路由/中间件
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

// 先执行中间件,再处理getlocation路由
router.post("/postUserDirectionAndLineNumberAndDeviceId", attachMetroInfo, (req, res) => {
  res.status(200).json({ message: "User direction received successfully" });
});

router.post("/getlocation", (req, res) => {
  try {
    const { directionNumber, deviceId, metroNumberChoice } = req.metroInfo;
    console.log("deviceId", deviceId);
    console.log(
      "directionNumber:", directionNumber,
      "metroNumberChoice:", metroNumberChoice,
      "deviceId:", deviceId
    );

    // 执行你的findMetro逻辑
    // const metro = await Station.find(...)
    
    res.status(200).json({ /* 返回数据 */ });
  } catch (error) {
    console.log(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
});

场景2:两个路由是独立请求

如果两个路由是用户发起的两次独立请求(比如先提交信息,之后再调用获取位置),中间件无法直接共享变量,此时需要用会话存储或缓存/数据库:

  1. 会话存储:用express-session将用户信息存在服务端会话中,后续请求通过会话ID(可放在请求头或Cookie中)获取数据
  2. 缓存/数据库:以deviceId为键,将用户地铁信息存在Redis或数据库中,后续请求携带deviceId查询数据

示例(Redis缓存方案):

const redis = require("redis");
const client = redis.createClient();

// 提交信息路由:存储到Redis
router.post("/postUserDirectionAndLineNumberAndDeviceId", async (req, res) => {
  try {
    const { direction, deviceId, metroNumberChoice } = req.body;
    await client.setEx(`metro:${deviceId}`, 3600, JSON.stringify({
      directionNumber: direction,
      metroNumberChoice
    }));
    res.status(200).json({ message: "User direction received successfully" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
});

// 获取位置路由:从Redis读取
router.post("/getlocation", async (req, res) => {
  try {
    const { deviceId } = req.body; // 客户端需要携带deviceId
    const metroInfoStr = await client.get(`metro:${deviceId}`);
    if (!metroInfoStr) {
      return res.status(400).json({ message: "No metro info found for this device" });
    }
    const { directionNumber, metroNumberChoice } = JSON.parse(metroInfoStr);
    
    console.log("deviceId", deviceId);
    console.log(
      "directionNumber:", directionNumber,
      "metroNumberChoice:", metroNumberChoice,
      "deviceId:", deviceId
    );

    // 执行你的业务逻辑
    res.status(200).json({ /* 返回数据 */ });
  } catch (error) {
    console.log(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
});

三、总结

  • 绝对不要用全局变量存储请求级别的用户数据,会引发并发冲突
  • 同一次请求链内共享变量:用中间件挂载到req对象
  • 跨请求共享用户数据:优先用会话存储或缓存/数据库

内容的提问来源于stack exchange,提问作者Bilel Rahmouni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:21:29