一、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 = method
this.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