用Observable替换中间件模式(取消订阅吗?)

时间:2019-01-21 15:12:11

标签: javascript rxjs observable

在许多框架中都有使用中间件的通用方法。

ExpressJS中-我在这里用middleware-chain处理请求:

app.use('/url', middleware1);
app.use('/url', middleware2);
app.use('/url', middleware3);

Telegraf中-在这里,我使用middleware-chain处理消息事件(作为机器人):

bot.on('text', middleware1);
bot.on('text', middleware2);
bot.on('text', middleware3);

以上示例工作正常,我想实现以推迟一些请求/事件。在这种情况下,如果我的middleware-chain目前正忙于处理某些请求/事件-我可以将新的传入事件/请求存储在DB中,并在以后middleware-chain空闲时进行处理。这样做的主要原因是限制了某些用户一次仅发送一个请求/事件,并在middleware-chain忙时等待响应。

让我们假设我可以在数据库中存储/检索我需要的任何东西。但是,如果我从数据库中检索了一些请求/事件,则希望通过我的所有中间件发送/传递该请求/事件。在这种情况下,如果框架不支持此功能,则需要重新实现事件冒泡。

但是我可以为此使用Observable。

ExpressJS:

const sbj = new Subject();

app.use('/url', (...args) => {
  sbj.next(args)
});

observable.subscribe({
  next: middleware1
});
observable.subscribe({
  next: middleware2
});
observable.subscribe({
  next: middleware3
});

Telegraf:

const sbj = new Subject();

bot.on('text', (...args) => {
  sbj.next(args)
});

observable.subscribe({
  next: middleware1
});
observable.subscribe({
  next: middleware2
});
observable.subscribe({
  next: middleware3
});

但是我错过了Observable-chainmiddleware-chain =>中的一项重要功能,我可以取消下一个中间件。例如。 middleware-chain

如何使用middleware1 -> next -> middleware2 -> cancel实现相同的行为(因此一个订阅可以取消另一个订阅)?我认为应该有一个优雅的解决方案。

2 个答案:

答案 0 :(得分:2)

RxJS有其自己的“链接”机制,称为管道运算符as you can see here为您提供了一系列的服务。如果您具有可重用的中间件,则可以很好地将它们实现为自己的操作员。例如,身份验证运算符可能如下所示:

function authenticator() = (obs$) => obs$.pipe(
  mergeMap(([req, res]) => req.isAuthenticated() ? of([req, res]) : throwError([res, "Must be authenticated!"]))
)

然后,您可以按以下方式使用它:

const sbj = new Subject();

app.use('/url', (...args) => {
  sbj.next(args)
});

sbj.pipe(
   authenticator(),
   // more operators
).subscribe(([req, res]) => {
   // send response
}, ([res, err]) => {
   // send error
})

答案 1 :(得分:0)

没有可观察的表达,请提供next('route')以便您跳过中间件链 https://expressjs.com/en/guide/using-middleware.html

var app = express()
var router = express.Router()

// predicate the router with a check and bail out when needed
router.use(function (req, res, next) {
  if (!req.headers['x-auth']) return next('router')
  next()
})

router.get('/', function (req, res) {
  res.send('hello, user!')
})

// use the router and 401 anything falling through
app.use('/admin', router, function (req, res) {
  res.sendStatus(401)
})