文章目錄
前情概要
在使用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實作。