Глобальная служба Node typescript для возврата значения из функции

Я пытаюсь реализовать службу для своего бэкэнда, которая позволяет вызывать данные сеанса из любого места кода, а это означает, что я хочу создать служебный файл, который экспортирует значения из функций, которые получают данные сеанса. В противном случае я могу получить данные сеанса только из внутренних функций, которые имеют параметры req: Request и res: Response. Итак, я в основном пытаюсь заблокировать значения переменной, которую можно использовать и вызывать из любого места в моем проекте. Мой код теперь выглядит так, но если я использую экспорт в любом другом месте файла, он просто печатает фактический фрагмент кода (функции) вместо возвращаемого значения, указанного внутри кода. Я новичок в машинописном тексте и узле в целом, а это значит, что я могу делать здесь действительно глупые ошибки.

Заранее спасибо за помощь! /Виктор

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.info(redisKey);
    getRedis(redisKey, function success(reply: any) {
        res.status(200).json(
            JSON.parse(reply)
        );
}, function error(err: Error) {
    console.info("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.info(redisKey);
    getRedis(redisKey, function success(reply: any) {
        res.status(200).json(
            JSON.parse(reply)
        );
}, function error(err: Error) {
    console.info("Something went wrong");
});
}

Я хочу, чтобы он работал как в первом примере, поскольку в моем коде есть несколько экземпляров, в которых я хочу получить доступ к данным без необходимости передавать параметры req, res, если это возможно.

записать данные в БД или в файл

NuOne 18.12.2018 09:08

Но данные изменяются «на лету», поскольку файлы cookie хранятся только в течение сеанса или максимум 1 день. Хранить данные в другом месте кажется небезопасным с точки зрения безопасности, потому что тогда данные пользователя хранятся где-то и могут подвергнуться внешним угрозам.

madvic 18.12.2018 09:17

так что очистить данные после того, как сеанс termantes

NuOne 18.12.2018 09:25
Это кажется небезопасным с точки зрения безопасности - это рискованно, если база данных может быть раскрыта. Собираетесь ли вы хранить все конфиденциальные пользовательские данные в оперативной памяти из соображений безопасности?
Estus Flask 18.12.2018 09:42

Прямо сейчас я фактически реализовал redisstore, чтобы данные где-то хранились, но для доступа к данным мне все равно нужно использовать req.session, что означает, что он должен находиться внутри функции с параметром req: Request. У меня все еще возникают проблемы, чтобы найти способ обойти это. Redisstore генерирует случайный ключ для каждого сеанса, но кажется излишним сохранять этот ключ где-нибудь, а затем использовать функцию client.get redis для доступа к данным сеанса, потому что тогда мне пришлось бы где-то сохранить случайно сгенерированный ключ и сопоставить его с сеансом нет?

madvic 18.12.2018 09:46

@madvic как вы используете экспортированные функции? Добавьте этот фрагмент к своему вопросу, пожалуйста.

Lukas Knuth 18.12.2018 09:47

Кроме того, используете ли вы промежуточное ПО для создания сеанса или делаете это сами?

Lukas Knuth 18.12.2018 09:48

@LukasKnuth Добавил несколько примеров, большое спасибо за помощь! Я использую экспресс-сеанс для создания сеансов и redisstore (connect-redis) для хранения данных сеанса

madvic 18.12.2018 09:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
567
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете записывать данные в базу данных или в файл, как говорят madvic, но мы также можем использовать глобальные переменные. Но глобальные переменные - это плохая практика, насколько я знаю, поэтому лучше кому-нибудь свои данные записать.

Ответ принят как подходящий

Во-первых, краткое объяснение сессий:

  • Когда пользователь входит в систему (и вы проверяете его учетные данные и т. д.), Вы запускаете новый сеанс для этого пользователя.
  • Программное обеспечение промежуточного слоя, которое вы используете, назначит этому сеансу уникальный идентификатор, и вы можете назначить ему некоторые данные.
    • Я БЫ передается в браузер пользователя в виде файла cookie.
    • Данные хранится на сервере (в Redis для вашего случая)
  • По промежуточного слоя проверяет, включен ли в запрос файл cookie сеанса с действительным идентификатором, и выполняет следующие действия:
    • Получить Session-Данные для данного Я БЫ из Redis
    • Заполните объект req.session с помощью Данные из Redis
    • Вызов следующего маршрута

Небольшой совет: не храните данные сеанса в памяти приложений. Почему? Данные должны быть актуальны только в контексте запроса от пользователя. Вам понадобятся данные сеанса для обработки запроса, но в противном случае они вам не понадобятся.

Вместо того, чтобы хранить его глобально, создайте свои обработчики и функции так, чтобы они принимали конкретный Session-Данные в качестве параметров, например:

// 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. Эти (почти) чистые функции упрощают понимание вашего кода

Если вы пишете функции, которые полностью работают со своими входными параметрами и не используют какое-либо глобальное состояние, такие вещи, как «порядок вызова функций» или «проверка наличия данных» становятся неактуальными. Вызывающий отвечает за получение данных, вызываемый отвечает за работу с ними.

Расширяя это, экспресс-маршруты должны никогда не используйте какие-либо глобальные данные в памяти, если вы когда-нибудь захотите масштабировать свое приложение по горизонтали (используя несколько экземпляров). Нельзя гарантировать, что один и тот же клиент всегда будет подключаться к одному и тому же экземпляру сервера, поэтому глобально сохраненные данные могут быть доступны для одного запроса, но не для следующего. В этом случае вам нужно будет найти способ обмена глобальными данными между всеми вашими экземплярами, что Redis уже делает в вашем случае.


tl; dr: Доступ к данным сеанса только в обработчике запросов, а затем передача их в качестве параметров любым функциям, которые должны с ними работать. Не сохраняйте глобальное состояние в памяти на своем сервере, если вы когда-нибудь захотите масштабировать его по горизонтали.

Большое спасибо за помощь, очень признателен! Итак, если я правильно понял, я могу отформатировать все свои выборки таким образом, и (в данном случае) const getUserBio затем будет использоваться в любом месте моего кода, когда я хочу получить доступ к биоданным. Однако мой последующий вопрос заключается в том, что не означает ли это, что когда я использую константу getUserBio в другом месте, мне все равно нужно передавать параметры? Или, если я, например, просто использую console.info (getUserBio), он не будет распечатывать значения, возвращаемые функцией, я прав? Простите, если эти вопросы кажутся глупыми, я новичок в node.js и javascript / typescript / V

madvic 18.12.2018 13:24

а) Да, вы правы, вам нужно будет каждый раз передавать параметры. Я надеюсь, что это прозвучит в ответе, но: не должно быть причин, чтобы эта функция была где-то еще. Все ваше приложение в основном представляет собой «код запуска при поступлении пользовательского запроса», поэтому вам не понадобятся данные, если нет соответствующего пользовательского запроса.

Lukas Knuth 18.12.2018 13:29

б) Если вы напечатаете console.info(getUserBio), это напечатает строковое представление функции. Чтобы было понятно, это не вызывает функция! Функции в JavaScript / TypeScript - это примитивы, такие как number или string, поэтому вы можете передавать их в качестве параметров и назначать их переменным.

Lukas Knuth 18.12.2018 13:31

Большое спасибо, Лукас! Это проясняет кучу вещей, о которых я думал. Просто из любопытства, если бы я хотел использовать функцию без параметров, есть ли какой-нибудь чистый способ сохранить возвращаемое значение функции в переменной или что-то подобное, что я могу просто вызвать в любом месте моего кода без параметров? Я задумывался об этом некоторое время и так и не нашел четкого решения. Еще раз спасибо за вашу помощь! /Виктор

madvic 20.12.2018 10:02

@madvic не уверен, что понимаю. Почему вы не можете присвоить значение, возвращаемое функцией (вызываемое с параметрами), переменной? Если вы хотите, чтобы это было доступно по всему миру, нет хорошего способа сделать это. Серверы отличаются от клиентских приложений тем, что вы не знаете, будет ли следующее взаимодействие с тем же человеком. Таким образом, наличие состояния в памяти обычно является плохой идеей и приводит к случайной утечке данных (когда вы показываете данные не тому пользователю).

Lukas Knuth 20.12.2018 15:27

Да, я думал о том, чтобы сделать это глобально доступным, но, как вы говорите, это не очень хорошая идея. Ваш способ кажется намного лучше, и поскольку мое приложение масштабируется по горизонтали, я понял, что глобальные переменные действительно плохи (как вы и говорите, потому что взаимодействия могут смешиваться). Спасибо за все, Лукас, я многому научился и знаю, что делать, а чего не делать! Еще раз спасибо и удачного Рождества и отличного Нового года! С уважением, / Виктор

madvic 21.12.2018 08:12

Другие вопросы по теме