节点打字稿全局服务到函数的 return 值

Node typescript global service to return value from a function

我正在尝试为我的后端实现一个服务,允许从代码中的任何地方调用会话数据,这意味着我想创建一个服务文件,从获取会话的函数中导出值数据。否则我只能从同时具有 req: Request 和 res: Response 参数的函数内部获取会话数据。所以我基本上是在尝试将值锁定到一个可以在我的项目中的任何地方使用和调用的变量。我的代码现在看起来像这样,但是如果我在文件的其他任何地方使用导出,它只会打印实际代码(函数)片段而不是代码中指定的 return 值。一般来说,我对打字稿和节点还很陌生,这意味着我可能会在这里犯一些非常愚蠢的错误。

提前感谢大家的帮助! /维克多

import { Request, Response, NextFunction } from "express";

function getUserSessionData(req: Request, res: Response) {
    const userData = res.status(200).send(req.session.userData);
    return userData;
}
function getUserSessionLang(req: Request, res: Response) {
    const userLang = res.status(200).send(req.session.language);
   return userLang;
}
function getUserSessionAll(req: Request, res: Response) {
    const userAll = res.status(200).send(req.session);
   return userAll;
}


module.exports = {
    userData: getUserSessionData,
    userLang: getUserSessionLang,
    userAll: getUserSessionAll
};

我希望它如何工作:

const sessionService = require("./services/sessionService");
function getStuff(req: Request, res: Response, next: NextFunction) {
    let redisKey;
    if (!req.session.language) {
         redisKey = "getStuffEN";
    }
    else {
         redisKey = "getStuff" + sessionService.userLang;
    }
    console.log(redisKey);
    getRedis(redisKey, function success(reply: any) {
        res.status(200).json(
            JSON.parse(reply)
        );
}, function error(err: Error) {
    console.log("Something went wrong");
});
}

这就是现在(和工作)的样子

function getStuff(req: Request, res: Response, next: NextFunction) {
    let redisKey;
    if (!req.session.language) {
         redisKey = "getStuffEN";
    }
    else {
         redisKey = "getStuff" + req.session.language;
    }
    console.log(redisKey);
    getRedis(redisKey, function success(reply: any) {
        res.status(200).json(
            JSON.parse(reply)
        );
}, function error(err: Error) {
    console.log("Something went wrong");
});
}

我希望它像第一个示例一样工作,因为在我的代码中有一些实例,我想访问数据而不必传递 req、res 参数,如果可能的话。

您可以将数据写入数据库或文件,就像 madvic 所说的那样,但我们也可以使用全局变量。但是全局变量是一种不好的做法,据我所知,所以最好把你的数据写给别人。

首先,对session做一个简短的解释:

  • 当用户登录(并且您验证他的凭据等)时,您会为该用户启动一个新会话。
  • 您使用的中间件将为该会话分配一个唯一的 ID,您可以为其分配一些数据。
    • ID 以 cookie
    • 的形式传输到用户浏览器
    • 数据 存储在服务器上(在您的情况下在 Redis 中)
  • 中间件将检查请求中是否包含具有有效 ID 的会话 cookie,并执行以下操作:
    • 从 Redis
    • 获取给定 ID 的会话-数据
    • 使用来自 Redis
    • Data 填充 req.session-对象
    • 调用下一条路线

除此之外,忠告一句:不要将会话数据存储在应用程序内存中。为什么?数据应该只与用户请求的上下文相关。您将需要会话数据来处理请求,但您不需要它。

与其将其全局存储,不如构建您的处理程序和函数以接受特定的 Session-Data 作为参数,如下所示:

// handler, after middleware:
const getUserBio = (req, res) => {
    const userId = req.session.userId;
    const bioData = fetchBio(userId);
    res.render("userBio", bioData);
}

// somewhere else in your code
function fetchBio(userId) {
    const fullBio = database.fetchBio(userId);
    return {
        full: fullBio,
        excerpt: fullBio.substring(0, 24);
    }
}

这有两个重要的优点:

  1. 您不必将内存中的会话-数据与Redis
  2. 中的会话保持同步
  3. 这些(几乎)pure functions让你的代码更容易理解

如果您编写的函数完全根据输入参数工作并且不使用任何全局状态,那么 "order in which to call functions" 或 "check if data is available" 之类的东西就变得无关紧要了。调用者负责获取数据,被调用者负责处理数据。

在此基础上扩展,如果您想水平扩展您的应用程序(通过使用多个实例),快速路由应该永远不要使用任何全局内存数据。不能保证同一个客户端将始终连接到同一个服务器实例,因此全局存储的数据可能可用于一个请求但不能用于下一个请求。在这种情况下,您必须找到一种在所有实例之间共享全局数据的方法,这正是 Redis 在您的情况下所做的。


tl;dr: 仅访问请求处理程序中的会话数据,然后将其作为参数传递给需要处理它的任何函数。如果您想水平扩展服务器,请不要在服务器中保留全局内存状态。