Как объединить два промежуточных ПО и экспортировать их как одно?

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

Служебный файл

const axios             = require("axios");
const requestIp         = require("request-ip");

const getDeviceLocation = async (req, res, next) => {
    try {
        // ToDO: Check if it works on production
        const clientIp  = requestIp.getClientIp(req);
        const ipToCheck = clientIp === "::1" || "127.0.0.1" ? "" : clientIp;

        const details = await axios.get("https://geoip-db.com/json/" + ipToCheck);

        // Attach returned results to the request body
        req.body.country    = details.data.country_name;
        req.body.state      = details.data.state;
        req.body.city       = details.data.city;

        // Run next middleware
        next();
    }
    catch(error) {
        return res.status(500).json({ message: "ERROR_OCCURRED" });
    }
};

const getDeviceClient = async (req, res, next) => {
    const userAgent = req.headers["user-agent"];

    console.info("Device UA: " + userAgent);
    next();
};

module.exports = { getDeviceLocation, getDeviceClient };

Примеры маршрутов

app.post("/v1/register", [getDeviceLocation, getDeviceClient, Otp.verify], User.create);

app.post("/v1/auth/google", [getDeviceLocation, getDeviceClient, Auth.verifyGoogleIdToken], Auth.useGoogle);  

Я бы хотел, чтобы getDeviceLocation и getDeviceClient были объединены в одно слово getDeviceInfo, но при этом иметь возможность использовать getDeviceLocation и getDeviceClient по отдельности, когда это необходимо на любом маршруте.

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
1 924
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Используя connect nodemodule, вы можете объединить промежуточное ПО и предоставить для него новую конечную точку. Ссылайтесь на пример кода https://blog.budiharso.info/2015/07/28/Combine-multiple-express-middleware/

Да, я прошел через это, прежде чем спрашивать здесь, но он запрашивает пакет подключения. Есть ли другой альтернативный способ сделать это?

Ayan 01.06.2019 18:25

В коде, который вы разместили, вы следуете цепочке нескольких вызовов промежуточного программного обеспечения без использования какого-либо стороннего модуля Ref: stackoverflow.com/questions/31928417/…

Senthil 01.06.2019 18:34

Если вы все еще хотите предоставить другой маршрут, то используйте сторонние модули узлов, такие как Combine, compose-middleware, middleware-flow.

Senthil 01.06.2019 18:35

Как вы думаете, какой из них лучше. Я не использовал ни один из них.

Ayan 01.06.2019 18:37

комбинировать лучше

Senthil 01.06.2019 18:49
Ответ принят как подходящий

В вашем случае, возможно, вы можете использовать что-то простое, как это

const getDeviceInfo = async (req, res, next) => {
    await getDeviceClient(req, res, async () => {
        await getDeviceLocation(req, res, next)
    })
}

Но вам может понадобиться обрабатывать случаи ошибок.

В этом случае, я думаю, я не смогу использовать отдельные функции независимо.

Ayan 01.06.2019 19:22

нет, вы все еще можете использовать их! вы просто создаете это как еще одну функцию/промежуточное программное обеспечение.

Rami Jarrar 01.06.2019 19:23

Можно ли использовать с ожиданием?

Ayan 01.06.2019 19:28

что ты имеешь в виду?!

Rami Jarrar 01.06.2019 19:29

Я имел в виду, можно ли это сделать как await getDeviceClient(req, res, next); await getDeviceLocation(req, res, next);

Ayan 01.06.2019 19:31

нет, если вы хотите использовать отдельные функции независимо

Rami Jarrar 01.06.2019 19:33

На самом деле моя IDE говорит Promise returned is ignored, поэтому я подумал спросить.

Ayan 01.06.2019 19:34

ах, вот почему я сказал вам But you may need to handle error cases., но в любом случае, чтобы удалить эту ошибку, просто добавьте ожидание перед каждым вызовом, я обновлю ответ

Rami Jarrar 01.06.2019 19:36

Я предполагаю, что вам не хватает асинхронного оператора в первой функции ожидания.

Ayan 01.06.2019 19:46

:) Похоже, это то, что я хотел. Спасибо.

Ayan 01.06.2019 19:50

Если вы хотите избежать ада обратного вызова, вы можете использовать что-то вроде этого:

const nextInterceptor = error => {
  if (error) { throw error; }
};

const combineMiddlewares = middlewares => (req, res, next) => (
  middlewares.reduce((previousMiddleware, currentMiddleware) => (
    previousMiddleware.then(() => currentMiddleware(req, res, nextInterceptor))
  ), Promise.resolve())
    .then(() => next())
    .catch(next)
);

const commonMiddlewares = combineMiddlewares([getDeviceLocation, getDeviceClient]);

app.post("/v1/register", [commonMiddlewares, Otp.verify], User.create);
app.post("/v1/auth/google", [commonMiddlewares, Auth.verifyGoogleIdToken], Auth.useGoogle);

Express позволяет вам использовать объявить промежуточное ПО в массиве, поэтому вы можете просто определить массив промежуточных программ, которые вы хотите объединить:

const getDeviceLocation = async (req, res, next) => {
...
};

const getDeviceClient = async (req, res, next) => {
...
};

const getDeviceInfo = [getDeviceLocation, getDeviceClient];

module.exports = { getDeviceLocation, getDeviceClient, getDeviceInfo };

Затем вы можете использовать любую комбинацию одного или обоих промежуточных программ, где хотите:

app.use('/foo', getDeviceLocation, () => {});
app.use('/bar', getDeviceClient, () => {});
app.use('/baz', getDeviceInfo, () => {});

Это просто и не требует установки ничего. Просто используйте:

const {Router} = require('express')

const combinedMiddleware = Router().use([middleware1, middleware2, middleware3])

Теперь вы можете использовать комбинированное промежуточное ПО там, где это необходимо. Например:

app.get('/some-route', (req, res, next) => {
  req.query.someParam === 'someValue'
    ? combinedMiddleware1(req, res, next)
    : combinedMiddleware2(req, res, next)
})

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