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





Используя connect nodemodule, вы можете объединить промежуточное ПО и предоставить для него новую конечную точку. Ссылайтесь на пример кода https://blog.budiharso.info/2015/07/28/Combine-multiple-express-middleware/
В коде, который вы разместили, вы следуете цепочке нескольких вызовов промежуточного программного обеспечения без использования какого-либо стороннего модуля Ref: stackoverflow.com/questions/31928417/…
Если вы все еще хотите предоставить другой маршрут, то используйте сторонние модули узлов, такие как Combine, compose-middleware, middleware-flow.
Как вы думаете, какой из них лучше. Я не использовал ни один из них.
комбинировать лучше
В вашем случае, возможно, вы можете использовать что-то простое, как это
const getDeviceInfo = async (req, res, next) => {
await getDeviceClient(req, res, async () => {
await getDeviceLocation(req, res, next)
})
}
Но вам может понадобиться обрабатывать случаи ошибок.
В этом случае, я думаю, я не смогу использовать отдельные функции независимо.
нет, вы все еще можете использовать их! вы просто создаете это как еще одну функцию/промежуточное программное обеспечение.
Можно ли использовать с ожиданием?
что ты имеешь в виду?!
Я имел в виду, можно ли это сделать как await getDeviceClient(req, res, next); await getDeviceLocation(req, res, next);
нет, если вы хотите использовать отдельные функции независимо
На самом деле моя IDE говорит Promise returned is ignored, поэтому я подумал спросить.
ах, вот почему я сказал вам But you may need to handle error cases., но в любом случае, чтобы удалить эту ошибку, просто добавьте ожидание перед каждым вызовом, я обновлю ответ
Я предполагаю, что вам не хватает асинхронного оператора в первой функции ожидания.
:) Похоже, это то, что я хотел. Спасибо.
Если вы хотите избежать ада обратного вызова, вы можете использовать что-то вроде этого:
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)
})
Да, я прошел через это, прежде чем спрашивать здесь, но он запрашивает пакет подключения. Есть ли другой альтернативный способ сделать это?