Express簡介
是一個簡潔、靈活的node.js Web應用開發框架,是目前最流行的基于Node.js的Web開發框架. 它提供一系列強大的功能,比如:
- 模板解析
- 靜態文件服務
- 中間件
- 路由控制
還可以使用其他模塊來幫助你創建各種Web和移動設備應用
簡單創建一個express
首先需要提供一個工廠函數,創建app,之后的多項功能將在該app對象上添加
function createApplication(){
let app = function(req,res){};
return app;
}
路由實現
express一個最重要的功能即是定義路由規則,通過對這些規則的匹配返回不同的內容
首先我們需要一種叫router
(路由容器)的東西來存放具體的route
const Route = require('./route');
const Layer = require('./layer');
const url = require('url');
const methods = require('methods');
const init = require('../middle/init');
const slice = Array.prototype.slice;
//let r = Router()
//let r = new Router();
function Router() {
function router(req, res, next) {
router.handle(req, res, next);
}
Object.setPrototypeOf(router, proto);
router.stack = [];
//聲明一個對象,用來緩存路徑參數名它對應的回調函數數組
router.paramCallbacks = {};
//在router一加載就會加載內置 中間件
// query
router.use(init);
return router;
}
let proto = Object.create(null);
//創建一個Route實例,向當前路由系統中添加一個層
proto.route = function (path) {
let route = new Route(path);
let layer = new Layer(path, route.dispatch.bind(route));
layer.route = route;
this.stack.push(layer);
return route;
}
proto.use = function (path, handler) {
if (typeof handler != 'function') {
handler = path;
path = '/';
}
let layer = new Layer(path, handler);
layer.route = undefined;//我們正是通過layer有沒有route來判斷是一個中間件函數還是一個路由
this.stack.push(layer);
}
methods.forEach(function (method) {
proto[method] = function (path) {
let route = this.route(path);//是在往Router里添一層
route[method].apply(route, slice.call(arguments, 1));
return this;
}
});
proto.param = function (name, handler) {
if (!this.paramCallbacks[name]) {
this.paramCallbacks[name] = [];
}
// {uid:[handle1,hander2]}
this.paramCallbacks[name].push(handler);
}
/**
* 1.處理中間件
* 2. 處理子路由容器
*/
proto.handle = function (req, res, out) {
//slashAdded是否添加過/ removed指的是被移除的字符串
let idx = 0, self = this, slashAdded = false, removed = '';
// /user/2
let { pathname } = url.parse(req.url, true);
function next(err) {
if (removed.length > 0) {
req.url = removed + req.url;
removed = '';
}
if (idx >= self.stack.length) {
return out(err);
}
let layer = self.stack[idx++];
//在此匹配路徑 params 正則+url= req.params
if (layer.match(pathname)) {// layer.params
if (!layer.route) { //這一層是中間件層// /user/2
removed = layer.path;// /user
req.url = req.url.slice(removed.length);// /2
if (err) {
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
} else {
if (layer.route && layer.route.handle_method(req.method)) {
//把layer的parmas屬性拷貝給req.params
req.params = layer.params;
self.process_params(layer, req, res, () => {
layer.handle_request(req, res, next);
});
} else {
next(err);
}
}
} else {
next(err);
}
}
next();
}
//用來處理param參數,處理完成后會走out函數
proto.process_params = function (layer, req, res, out) {
let keys = layer.keys;
let self = this;
//用來處理路徑參數
let paramIndex = 0 /**key索引**/, key/**key對象**/, name/**key的值**/, val, callbacks, callback;
//調用一次param意味著處理一個路徑參數
function param() {
if (paramIndex >= keys.length) {
return out();
}
key = keys[paramIndex++];//先取出當前的key
name = key.name;// uid
val = layer.params[name];
callbacks = self.paramCallbacks[name];// 取出等待執行的回調函數數組
if (!val || !callbacks) {//如果當前的key沒有值,或者沒有對應的回調就直接處理下一個key
return param();
}
execCallback();
}
let callbackIndex = 0;
function execCallback() {
callback = callbacks[callbackIndex++];
if (!callback) {
return param();//如果此key已經沒有回調等待執行,則意味本key處理完畢,該執行一下key
}
callback(req, res, execCallback, val, name);
}
param();
}
module.exports = Router;
/**
* Router
* stack
* layer
* path route
* method handler
* Layer
* Router Layer 路徑 處理函數(route.dispatch) 有一個特殊的route屬性
* Route layer 路徑 處理函數(真正的業務代碼) 有一特殊的屬性method
*/
/**
* 1.params param
2.模板引擎 我們會自己寫一個模板支持,邏輯判斷 。if while do
*/