一、Express 源码的目录结构
首先,会去package.json项目(包)描述文件中寻找main属性的值,
main:入口文件。这个main的值就是入口文件所在的路径。
这里并没有配置main属性的值,默认会去找index.js文件作为入口文件
二、快速体验
const http = require('http')
const url = require('url')
const routes = [/*{ path: '', method: '', handler: () => {} }*/]
function createApplication() {return {get (path, handler) {routes.push({path,method: 'get',handler})},listen (...args) {const server = http.createServer((req, res) => {const { pathname } = url.parse(req.url)const method = req.method.toLowerCase()const route = routes.find(route => route.path === pathname && route.method === method)if (route) {return route.handler(req, res)}res.end('404 Not Found.')})server.listen(...args)}}
}
module.exports = createApplication
三、抽取App模块
const http = require('http')
const url = require('url')
function App() {this.routes = []
}
// const routes = [/*{ path: '', method: '', handler: () => {} }*/]
App.prototype.get = function (path, handler) {this.routes.push({path,method: 'get',handler})
}
App.prototype.listen = function (...args) {const server = http.createServer((req, res) => {const {pathname} = url.parse(req.url)const method = req.method.toLowerCase()const route = this.routes.find(route => route.path === pathname && route.method === method)if (route) {return route.handler(req, res)}res.end('404 Not Found.')})server.listen(...args)}
module.exports = App
四、提取路由模块
const url = require('url')let Router = function Router() {this.stack = []
}Router.prototype.get = function(path, handler){this.stack.push({path,method: 'get',handler})
}
Router.prototype.handle = function(req, res){const {pathname} = url.parse(req.url)const method = req.method.toLowerCase()const route = this.stack.find(route => route.path === pathname && route.method === method)if (route) {return route.handler(req, res)}res.end('404 Not Found.')
}
module.exports = Router
const http = require('http')
const Router = require('./router/index.js')
let App = function App() {this._router = new Router()
}
// 把路由收集起来
App.prototype.get = function (path, handler) {this._router.get(path, handler)
}
App.prototype.listen = function (...args) {const server = http.createServer((req, res) => {this._router.handle(req, res)})server.listen(...args)
}
module.exports = App
五、处理不同的请求方法
六、更强大的路由路径匹配模式(基本实现)
const url = require('url')
const methods = require('methods')
const pathRegexp = require('path-to-regexp')
let Router = function Router() {this.stack = []
}
methods.forEach(method => {// Router.prototype.get = function(path, handler){Router.prototype[method] = function(path, handler){this.stack.push({path,method,handler})}
})
Router.prototype.handle = function(req, res){const {pathname} = url.parse(req.url)const method = req.method.toLowerCase()const route = this.stack.find(route => {const keys = []const regexp = pathRegexp(route.path, keys, {})const match = regexp.exec(pathname)return match && route.method === method})if (route) {return route.handler(req, res)}res.end('404 Not Found.')
}
module.exports = Router
七、处理动态路由路径参数
const url = require('url')
const methods = require('methods')
const pathRegexp = require('path-to-regexp')
let Router = function Router() {this.stack = []
}
methods.forEach(method => {// Router.prototype.get = function(path, handler){Router.prototype[method] = function(path, handler){this.stack.push({path,method,handler})}
})
Router.prototype.handle = function(req, res){const {pathname} = url.parse(req.url)const method = req.method.toLowerCase()const route = this.stack.find(route => {const keys = []const regexp = pathRegexp(route.path, keys, {})const match = regexp.exec(pathname)console.log('keys=>', keys)console.log('match=>', match)if (match) {req.params = req.params || {}keys.forEach((key, index) => {req.params[key.name] = match[index + 1]})}return match && route.method === method})if (route) {return route.handler(req, res)}res.end('404 Not Found.')
}
module.exports = Router
八、提取Layer处理模块
const url = require('url')
const methods = require('methods')
const Layer = require('./layer.js')
let Router = function Router() {this.stack = []
}
methods.forEach(method => {// Router.prototype.get = function(path, handler){Router.prototype[method] = function(path, handler){const layer = new Layer(path ,handler)layer.method = methodthis.stack.push(layer)}
})
Router.prototype.handle = function(req, res){const {pathname} = url.parse(req.url)const method = req.method.toLowerCase()const route = this.stack.find(layer => {const match = layer.match(pathname)if(match) {req.params = req.params || {}Object.assign(req.params, layer.params)}return match && layer.method === method})if (route) {return route.handler(req, res)}res.end('404 Not Found.')
}
module.exports = Router