且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

【nodejs】让nodejs像后端mvc框架(asp.net mvc )一样处理请求--自动路由篇(1/8)【route】

更新时间:2021-07-28 17:26:57

文章目录

前情概要

在使用express框架开发的时候,每加一个请求,都在增加一条route请求规则,类似于下面的代码,很烦有木有!

app.use('/myroute path', (req, res, next) => { //dosomething })
我们难道不能再智能一点点么,学习后端mvc框架一样,比如加个标记,或者默认规则直接自动映射嘛。约定胜于配置嘛!

我们的实现思路

  1. 拦截所有请求
  2. 根据我们的规则进行路由的匹配
  3. 调用匹配到的处理函数

拦截所有请求

这个太好办了,app.use('/') 搞定。参考下面的代码

import * as express from 'express'
import * as controllers from './controller'
import { RequestHandler, RouteHandler } from 'gd-express-basic'

const _app = express();
//第一个express 中间件,处理一下跨域请求中的options请求。
_app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With');
    res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
    if (req.method == 'OPTIONS') {
        res.send(new ResponseBase(200));
    }
    next && next();
});
//第二个中间件,拦截所有请求对路由做自动映射
RouteHandler(_app, controllers);
//第三个中间件,处理请求
_app.use(RequestHandler);
//第N个中间件,处理一下error呀,404呀等其他情况。

根据规则进行路由的匹配

接下来看一看RouteHandler方法。主要干几个事情

  1. 缓存所有action,方便后续的调用。【 请求处理函数的特性注册篇【详细说明】
  2. 拦截所有请求,并根据规则解析到对应的action上面去。【app.use('/', (req, res, next)】
  3. 根据解析出来的controller 、action名称以及当前请求的method找到对应的action并记录到当前请求对象上,方便接下来的请求处理。
    目前我们的规则很简单。url分2层,第一层为controller名称,第二层为action名称。即:/{controller}/{action};
/**
 * 路由选择处理中间件
 * 
 * @export
 * @param {core.Express} app 
 * @param {*} controllers 
 */
export function RouteHandler(app: core.Express, controllers: any) {
   //程序启动的时候,找到当前所有的controllers,并根据规则缓存好我们所有的处理函数(action),方便接下来的匹配
   //请求处理函数发现篇【controller+action】具体讲到
    find(controllers)
//拦截所有请求,对请求
    app.use('/', (req, res, next) => {
    //拿到route并解析出来controller和action的名称。
        var pathArr = getRouteTokens(req.path)
        var controller = (pathArr[0] && pathArr[0].toLowerCase()) || 'home';
        var action = (pathArr[1] && pathArr[1].toLowerCase()) || 'index'
        //根据参数找到能处理这个请求的action
        var desc = GetActionDescriptor(controller, action, req.method)
        if (!desc) {
            desc = GetActionDescriptor(controller, '_default', req.method)
        }
        if (desc && (!desc.HttpMethod || (desc.HttpMethod && desc.HttpMethod === req.method))) {

            res.locals.authInfo = { isAuth: desc.isAuth };
            //如果请求能匹配到可以处理的action,则赋值
            res.locals.actionDescriptor = desc;
        }else{//否则跳过。当然在这里也可以直接返回404,结束本次请求。
         }
        next && next()
    })
}

function getRouteTokens(path: string) {
    var pathArr = path.split('/');
    var arr: string[] = [];
    pathArr.forEach(element => {
        if (element) arr.push(element)
    });
    return arr
}

代码那是相当的简单。其实只干了一件事情,据我们的url规则找到与之匹配的在项目启动的时候扫描缓存的请求处理函数

  1. 考虑到前端不太会有area的概念,所以暂时没有支持,如果要支持其实也很简单,增加一个area注册,然后再做路由匹配的时候多判断一次area就完事儿了。
  2. 估计也不太会有自定义route 的要求,比如dotnet mvc 里面的【[Route("/path")]】特性。所以也暂未做支持。如果确实有也可以通过app.use实现。