博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手动实现 express
阅读量:6292 次
发布时间:2019-06-22

本文共 10285 字,大约阅读时间需要 34 分钟。

express 中文翻译 “快递”

  • 基于http服务进行了二次封装
  • 在express中扩展了很多 中间件
  • 对路由进行了封装
  • req,res 进行了一些功能的封装

关于express和koa中间件的区别

  • koa 小巧,仅做基础封装
  • express 有很多额外的中间件,路由

简单使用

需要安装npm install express express.js

let express = require('../node_modules/express');let app = express();app.get('/',(req,res)=>{  res.end('ok'+req.money);});app.get('/hello', (req, res) => {  res.end('hello');});app.delete('/hello', (req, res) => {  res.end('delete hello');});app.post('/hello',(req,res)=>{  res.end('post hello');});app.all('*',(req,res)=>{  res.end('end');});// 发送静态文件app.get('/404',function (req,res) {  res.sendFile('404.html',{
root:__dirname});//必须保证绝对路径 //res.sendFile(require('path').join(__dirname,'404.html'));})app.listen(3000);复制代码

上述我们可以看出:

  • express是一个函数
  • 函数有 delete, post,all等,处理路由
  • express执行后 返回的是一个监听函数
  • 该函数可以起服务
  • 在访问路由之前可以做很多事情 => 中间件

express架子 express/index.js

let http = require('http');let url = require('url');function createApplication(){    //若果请求方法,路径一致,则执行回调    let app = (req,res) => {        let reqMethod = req.method.toLowerCase();        let {pathname} = url.parse(req.url,true);        for(let i=0;i
{ app.routes.push({ method:'get', path, handler }) } app.listen = (...args) => { let server = http.createServer(app); server.listen(...args); } return app;}module.exports = createApplication复制代码

post测试:可以下载postman插件

all

function createApplication(){    ...    let app = (req,res) => {        ...        for(let i=0;i

洋葱模型

express/test1.js

function app(){}app.routes = [];app.use = function(cb){    app.routes.push(cb)}app.use((next)=> {    console.log(1);    next();    console.log(2);})app.use((next)=> {    console.log(3);    next();    console.log(4);})    app.use((next)=> {    console.log(5);    console.log(6);})  let index = 0;function next(){    if(index === app.routes.lenth) return;    app.routes[index++](next)}next();复制代码

输出135642,这就是我们说的洋葱模型

中间件

  • 中间件作用 当我们真正访问的路由之前可以干很多事情
  • 可以决定是否向下执行
  • 可以做一些权限判断,可以写多个中间件,和路由是放在同一个队列中的
  • req是同一个
  • 类似于洋葱模型

express.js

app.use('/', (req,res,next)=> {  req.money = 10000;  next();// 继续的意思,不调用next表示不继续了});app.use((req, res, next) =>{  req.money -= 2000;  next();});app.get('/',(req,res)=>{  res.end('ok'+req.money);});复制代码

最后 localhost:3000 输出ok 3000

中间件实现 express/index.js

...function createApplication(){    let app = (req,res) => {        let reqMethod = req.method.toLowerCase();        let {pathname} = url.parse(req.url,true);        let index = 0;        function next(){
//将回调转换为next形式 if(index === app.routes.length){ res.statusCode = 404; res.end(`Cannot ${reqMethod} ${pathname}`); return; } let {method,path,handler} = app.routes[index++]; if(method === 'middleware'){ //中间件 if(pathname == path || path === '/' || pathname.startsWith(path + '/')){ handler(req,res,next) }else{ next();// 没有迭代到 就执行下一个中间件 } }else{ //路由 if((method === reqMethod || method === all)&& (pathname == path|| pathname === '*')){ handler(req,res); }else{ next(); } } } next(); } app.routes = []; //存储 方法 路径 回调 let methods = ['get', 'post', 'put', 'delete', 'options']; app.use = function(path,handler){ if(typeof handler != 'function'){ handler = path; path = '/' } app.routes.push({ method: 'middleware', path, handler }) } ... return app;}module.exports = createApplication复制代码

有个特殊的地方,比如我们的路径是article/9/zdl,我们这样写article/:age/:name => {age:9,name:zdl}

如何解析这种路径?在express里可以通过req.params获取到

express.js

let express = require('../express');let app = express();app.get('/article/:id/:name', (req,res,next)=> {    console.log(req.params);    res.end(JSON.stringify(req.params));});app.listen(3000);复制代码

test: localhost:3000/:1/zdl1

express/index.js

...function createApplication(){    let app = (req,res) => {        ...        function next(){            ...            if(method === 'middleware'){                ...            }else{                //路由                if(path.params){                    // 到路径参数的路由                    if(path.test(pathname)){                        let params = {}                        let values = pathname.match(path).slice(1);                        values.forEach((value,index)=>{                            params[path.params[index]] = value                        });                        req.params = params; // 把参数挂载到req上                        handler(req,res);                    }else{                         next();                    }                }else{                    ...                }            }        }        next();    }    ...    methods.forEach(method => {        app[method] = (path,handler) => {            //带路径参数的路由            let params = [];            if(path.includes(':')){
//如果路径带有:就把路径转换成正则 path = path.replace(/:([^\/]+)/g,function(){ params.push(arguments[1]); return '([^\/]+)'; }) path = new RegExp(path); path.params = params; } app.routes.push({ method, path, handler }) } }) ... return app;}module.exports = createApplication复制代码

目录:

最后我们完整的index.js

let http = require('http');let url = require('url');function createApplication(){    //若果请求方法,路径一致,则执行回调    let app = (req,res) => {        let reqMethod = req.method.toLowerCase();        let {pathname} = url.parse(req.url,true);        let index = 0;        function next(){            if(index === app.routes.length){                res.statusCode = 404;                res.end(`Cannot ${reqMethod} ${pathname}`);                return;            }             let {method,path,handler} = app.routes[index++];            if(method === 'middleware'){                //中间件                if(pathname === path || path == '/' || pathname.startsWith(path + '/')){                    handler(req,res,next)                }else{                    next();//  没有迭代到 就执行下一个中间件                }            }else{                //路由                if(path.params){                    // 到路径参数的路由                    if(path.test(pathname)){                        let params = {}                        let values = pathname.match(path).slice(1);                        values.forEach((value,index)=>{                            params[path.params[index]] = value                        });                        req.params = params; // 把参数挂载到req上                        handler(req,res);                    }else{                         next();                    }                }else{                    if((method === reqMethod || method === all)&& (pathname == path|| pathname === '*')){                        handler(req,res);                    }else{                        next();                    }                }            }        }        next();    }    app.routes = [];    //存储 方法 路径 回调    let methods = ['get', 'post', 'put', 'delete', 'options'];    app.use = function(path,handler){        if(typeof handler != 'function'){            handler = path;            path = '/'        }        app.routes.push({            method: 'middleware',            path,            handler        })    }    app.all = function (path, handler) {        app.routes.push({            method: 'all',            path,            handler        })    }    methods.forEach(method => {        app[method] = (path,handler) => {            //带路径参数的路由            let params = [];            if(path.includes(':')){
//如果路径带有:就把路径转换成正则 path = path.replace(/:([^\/]+)/g,function(){ params.push(arguments[1]); return '([^\/]+)'; }) path = new RegExp(path); path.params = params; } app.routes.push({ method, path, handler }) } }) app.listen = (...args) => { let server = http.createServer(app); server.listen(...args); } return app;}module.exports = createApplication复制代码

中间件-1

express内置了很多中间件,把想要的方法已经解析好了,可以直接使用

let express = require('./express');let app = express();app.use(function (req,res,next) {  ...  next();});app.get('/article', (req,res,next)=> {  console.log(req.path,req.query);  res.send({
name:'zfpx'});});app.listen(3000);复制代码

实现 app.use的内容

test: localhost:3000/article?a=1&b=2

app.use(function (req,res,next) {    let {path,query} = url.parse(req.url,true);    req.path = path;    req.query = query;    req.hostname = 'XXXX';    //装饰模式    let end = res.end.bind(res);    res.send = function(value){        console.log(typeof value);        if(typeof value === 'object'){            end(JSON.stringify(value))        }else if(Buffer.isBuffer(value) || typeof value === 'string'){            end(value)        }else{            end(value.toString())        }            }    next();});复制代码

中间件-2

启用一个静态服务

index.js

let express = require('./express');let app = express();app.use(function (req,res,next) {  ...  next();});app.get('/article', (req,res,next)=> {  console.log(req.path,req.query);  res.send({
name:'zfpx'});});app.listen(3000);复制代码

use内容

let express = require('express');let app = express();let path = require('path');let fs = require('fs')function static(p){    return (req ,res ,next) => {        let newPath = path.join(p, req.path);        fs.stat(newPath,(err,stat) => {             if(err){                 next();             }else{                 console.log(stat.isDirectory());                                  if(stat.isDirectory()){                     let p = path.join(newPath,'/index.html');                     console.log(p);                                          fs.createReadStream(p).pipe(res)                 }else{                     fs.createReadStream(newPath).pipe(res)                 }             }        })    }}复制代码

转载地址:http://pxcta.baihongyu.com/

你可能感兴趣的文章
让人抓头的Java并发(一) 轻松认识多线程
查看>>
从源码剖析useState的执行过程
查看>>
地包天如何矫正?
查看>>
中间件
查看>>
Android SharedPreferences
查看>>
css面试题
查看>>
Vue组建通信
查看>>
用CSS画一个带阴影的三角形
查看>>
前端Vue:函数式组件
查看>>
程鑫峰:1.26特朗.普力挺美元力挽狂澜,伦敦金行情分析
查看>>
safari下video标签无法播放视频的问题
查看>>
01 iOS中UISearchBar 如何更改背景颜色,如何去掉两条黑线
查看>>
对象的继承及对象相关内容探究
查看>>
Spring: IOC容器的实现
查看>>
Serverless五大优势,成本和规模不是最重要的,这点才是
查看>>
Nginx 极简入门教程!
查看>>
iOS BLE 开发小记[4] 如何实现 CoreBluetooth 后台运行模式
查看>>
Item 23 不要在代码中使用新的原生态类型(raw type)
查看>>
为网页添加留言功能
查看>>
JavaScript—数组(17)
查看>>