文章目錄
前情概要
在使用express框架開發的時候,每加一個請求,都在增加一條route請求規則,類似於下面的代碼,很煩有木有!
app.use('/myroute path', (req, res, next) => { //dosomething }) 我們難道不能再智能一點點麼,學習後端mvc框架一樣,比如加個標記,或者默認規則直接自動映射嘛。約定勝於配置嘛!
我們的實現思路
- 攔截所有請求
- 根據我們的規則進行路由的匹配
- 調用匹配到的處理函數
攔截所有請求
這個太好辦了,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方法。主要幹幾個事情
- 緩存所有action,方便後續的調用。【 請求處理函數的特性註冊篇【詳細說明】
- 攔截所有請求,並根據規則解析到對應的action上面去。【app.use('/', (req, res, next)】
- 根據解析出來的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規則找到與之匹配的在項目啓動的時候掃描緩存的請求處理函數
- 考慮到前端不太會有area的概念,所以暫時沒有支持,如果要支持其實也很簡單,增加一個area註冊,然後再做路由匹配的時候多判斷一次area就完事兒了。
- 估計也不太會有自定義route 的要求,比如dotnet mvc 裏面的【[Route("/path")]】特性。所以也暫未做支持。如果確實有也可以通過app.use實現。