使用rxjs实现express的aop风格

前言

众所周知, express不像是koa, 不是洋葱皮结构的,所以如果你想在每个handle处理请求的函数结尾处进行一些操作, 你必须得在每个handle里都写,比如有时候你的有些接口会根据请求返回多一部分属性, 或者少一部分属性, 或者是res.json还是res.render, 或者你想统一处理返回数据的格式。这些还都是和req res里的一些东西相关联的, 你只能写一个函数来统一处理, 这就少不了一些if判断了。

nest.js就有一个interceptor的东西, 这里我们就简单实现一下, 看看rxjs如何解决这个问题

import express, {Request, Response, NextFunction, RequestHandler} from "express"
import {Observable} from "rxjs";
import {map, tap} from "rxjs/operators";

const app = express();
/* --------------------------------  我们需要关心, 写的部分start  ----------------------------------------- */
// 路由
app.get("/", wraper(_handle))

// 平时写得最多的处理函数
async function _handle(req: Request, res: Response, next: NextFunction) {
    return "hello aop";
}

// aop函数, 在这里我们可以在请求前和请求后统一处理一些东西
function aop(ctx: {req: Request, res: Response}, next: {handle: () => Observable}): Observable  {
    /* 
        do something with req/res
    */
    const time = Date.now();
    return next.handle().pipe(
        // 统一返回格式
        map(item => {
            return {
                msg: "ok",
                data: item,
                statusCode: 1,
            }
        }),
        // 请求耗时记录
        tap(() => console.log(`req ${ctx.req.originalUrl} takes ` + (Date.now() - time) + "ms"))
    )
}
/* --------------------------------  我们需要关心, 写的部分end ----------------------------------------- */

/* -------------------------------- 功能部分,只用写一次就行了start ------------------------------------ */
/**
 * 包裹函数, 将处理函数包裹在Observable里
 * @param handle 接收我们的处理函数为参数
 * @returns RequestHandler
 */
function wraper(handle: RequestHandler): RequestHandler {
    return (req: Request, res: Response, next: NextFunction) => {
        const contextHandle = {
            handle: function(): Observable  {
                return new Observable(subscrib => {
                    handle(req, res, next).then(
                        _res => {
                            subscrib.next(_res);
                            subscrib.complete()
                        }
                    )
                })
            }
        }
        aop({req, res}, contextHandle).subscribe({
            next(data) { 
                console.log('got value ' + JSON.stringify(data));
                res.json(data);
            },
            error(err) { console.error('something wrong occurred: ' + err); },
            complete() { console.log('done'); }
        });
    }
}
/* -------------------------------- 功能部分,只用写一次就行了end ------------------------------------ */
app.listen(7894, ()=>console.log("app launch"))

具体是怎么回事, 大家就看代码吧

你可能感兴趣的:(使用rxjs实现express的aop风格)