【问题标题】:Node typescript global service to return value from a function节点打字稿全局服务从函数返回值
【发布时间】:2018-12-18 17:24:13
【问题描述】:

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

提前感谢所有帮助! /维克多

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 参数的情况下访问数据。

【问题讨论】:

  • 将数据写入数据库或文件
  • 但数据是动态修改的,因为 cookie 仅存储会话持续时间或最多 1 天。将数据存储在其他任何地方感觉有点安全风险,因为这样用户数据存储在某个地方并且可能会受到外部威胁。
  • so clear data once session termantes
  • 在安全方面感觉有点冒险 - 如果数据库有机会暴露,那就是有风险的。出于安全考虑,您是否要将所有敏感的用户数据存储在 RAM 中?
  • 现在我实际上实现了一个 redisstore,以便将数据存储在某个地方,但是要访问数据我仍然必须使用 req.session 这意味着它需要在一个带有 req 的函数中:请求参数。我仍然很难找到绕过这个的方法。 redisstore 会为每个会话生成一个随机密钥,但是将密钥保存在某处然后使用 client.get redis 函数访问会话数据感觉有点过头了,因为我必须将随机生成的密钥保存在某处并匹配它会议,不是吗?

标签: node.js typescript global


【解决方案1】:

首先,关于会话的简短说明:

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

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

不要将其全局存储,而是构建您的处理程序和函数以接受特定的 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. 这些(几乎)pure functions 让您的代码更易于理解

如果您编写的函数完全使用其输入参数并且不使用任何全局状态,那么诸如“调用函数的顺序”或“检查数据是否可用”之类的内容将变得无关紧要。调用者负责获取数据,被调用者负责处理数据。

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


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

【讨论】:

  • 非常感谢您的帮助,非常感谢!因此,如果我理解正确,我可以以这种方式格式化我所有的提取,然后当我想访问 bioData 时,(在这种情况下)const getUserBio 在我的代码中的任何地方使用。然而,我的后续问题是,这是否意味着当我在其他地方使用 getUserBio const 时,我仍然必须传递参数?或者,例如,如果我只使用 console.log(getUserBio) 它不会打印出函数返回的值,对吗?请原谅,如果这些问题看起来很愚蠢,我对 node.js 和 javascript/typescript /V 还是很陌生
  • a) 是的,你是对的,你每次都需要传入参数。我希望它在答案中得到解决,但是:没有理由在其他任何地方都需要该功能。您的整个应用程序基本上是“当用户请求进来时运行代码”,因此如果没有关联的用户请求,您将不需要数据。
  • b) 如果你打印console.log(getUserBio),那将打印函数的字符串表示。需要明确的是,这不调用函数! JavaScript/TypeScript 中的函数是 numberstring 这样的原语,因此您可以将它们作为参数传递并分配给变量。
  • 非常感谢卢卡斯!这清除了我一直在想的一堆东西。只是出于好奇,如果我想使用没有参数的函数,是否有任何干净的方法可以将函数返回值存储到变量或类似的东西,我可以在没有参数的情况下在代码中的任何位置调用?我一直在想这个问题,但从未真正找到明确的解决方案。再次感谢你的帮助! /维克多
  • 是的,我正在考虑让它在全球范围内可用,但正如你所说,这不是一个好主意。你的方式似乎好多了,因为我的应用程序是水平可扩展的,我开始明白全局变量真的很糟糕(正如你所说,因为交互可能会混淆)。感谢 Lukas 所做的一切,我从中学到了很多,并且知道我知道该做什么,不该做什么!再次感谢,祝您圣诞节愉快,新年愉快!最好的问候,/维克多
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-08
    • 2016-03-27
    • 2019-10-12
    • 1970-01-01
    • 2014-04-12
    • 2019-03-06
    • 2018-07-30
    • 2022-01-12
    相关资源
    最近更新 更多