express基本原理
了解 express 原理之前,你需要先掌握 express 的基本用法。
关于 express 的介绍请看express 官网[1]。
基本结构
先回顾一下 express 使用的的过程,首先是把模块倒入,然后当做方法执行,在返回值中调用 use
处理路由,调用 listen
监听端口。
const express = require('express')
const app = express()
app.use('/home', (req, res) => { res.end('home')
})
app.listen(8080, () => { console.log('port created successfully')
})
根据上面的使用,我们开始构建代码。我们需要写一个 express 方法,返回一个 app
对象,有 use
和 listen
方法。
const http = require('http')
const url = require('url') function express() { const app = {} const routes = []; app.use = function (path, action) { routes.push([path, action]) } function handle(req, res) { let pathname = url.parse(req.url).pathname; for (let i = 0; i < routes.length; i++) { var route = routes[i]; if (pathname === route[0]) { let action = route[1]; action(req, res); return; } } handle404(req, res); } function handle404(req, res) { res.end('404') } app.listen = function (...args) { const server = http.createServer((req, res) => { handle(req, res) }) server.listen(...args) } return app
} module.exports = express
上面代码中的 use
方法的作用是把请求路径跟对应的处理函数存放在一个数组中,当请求到来的时候遍历数组,根据路径找到对应的方法执行。
动态路由
动态路由是根据参数可以动态匹配路径。
const express = require('./express')
const app = express() app.use('/home/:id', (req, res) => { res.end('home')
}) app.listen(8080, () => { console.log('port created successfully')
})
根据路由里面的参数要匹配符合规则的路由我们需要使用正则来处理,下面代码是根据路径来生成正则的一个方法。
const pathRegexp = (path, paramNames=[], {end=false} ={}) => { path = path .concat(end ? '' : '/?') .replace(/\/\(/g, '(?:/') .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function (_, slash, format, key, capture, optional, star) { slash = slash || ''; paramNames.push(key); return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + (optional || '') + (star ? '(/*)?' : ''); }) .replace(/([\/.])/g, '\\$1') .replace(/\*/g, '(.*)'); return new RegExp('^' + path + '$')
} module.exports = pathRegexp
根据路径生成正则也是有第三方模块path-to-regexp[2]模块,核心原理大家值得参考。包括 Vue 和 React 的路由都使用到了这个模块。
下面我们需要开始动态映射路由。
const http = require('http')
const url = require('url')
const pathRegexp = require('./pathRegexp') function express() { const app = {} const routes = { 'all': [] }; app.use = function (path, action) { const keys = [] const regexp = pathRegexp(path, keys,{end:true}) routes.all.push([ { regexp, keys }, action ]); }; ['get', 'put', 'delete', 'post'].forEach(function (method) { routes[method] = []; app[method] = function (path, action) { const keys = [] const regexp = pathRegexp(path, keys, {end:true}) routes[method].push([ { regexp, keys }, action ]); }; }); const match = function (pathname, routes, req, res) { for (var i = 0; i < routes.length; i++) { let route = routes[i]; let reg = route[0].regexp; let keys = route[0].keys; let matched = reg.exec(pathname); if (matched) { let params = {}; for (let i = 0, l = keys.length; i < l; i++) { let value = matched[i + 1]; if (value) { params[keys[i]] = value; } } req.params = params; let action = route[1]; action(req, res); return true; } } return false; }; function handle(req, res) { let {pathname, query} = url.parse(req.url, true); req.query = query let method = req.method.toLowerCase(); if (routes.hasOwnProperty(method)) { if (match(pathname, routes[method], req, res)) { return; } else { if (match(pathname, routes.all, req, res)) { return; } } } else { if (match(pathname, routes.all, req, res)) { return; } } handle404(req, res); } function handle404 (req, res) { res.end('404') } app.listen = function (...args) { const server = http.createServer((req, res) => { handle(req, res) }) server.listen(...args) } return app
} module.exports = express
其中 express 会把请求的方法都代理到 app 中作为属性的方式来方便用户使用。
const express = require('./express')
const app = express() app.use('/home/:id', (req, res) => { console.log(req.params) res.end('home')
}) app.get('/user', (req, res) => { console.log(req.query) res.end('user')
}) app.listen(8080, () => { console.log('port created successfully')
})
express 会在请求体中加一些属性,会把路径参数作为请求时的 params
属性,会把查询字符串作为请求时的 query
属性。大多数中间件也是这个原理,如 body-parser
模块,给它加个 body
属性即可。
通过GitHub查看代码请点击阅读原文
References
[1]
express 官网: http://expressjs.com/
[2]
path-to-regexp: https://github.com/pillarjs/path-to-regexp
express基本原理相关推荐
- express 源码阅读(全)
1. 简介 这篇文章主要的目的是分析理解express的源码,网络上关于源码的分析已经数不胜数,这篇文章准备另辟蹊径,仿制一个express的轮子,通过测试驱动的开发方式不断迭代,正向理解expres ...
- JWT(JSON Web Token)的基本原理
JWT(JSON Web Token)的基本原理 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案 一.跨域认证的问题 1.用户向服务器发送用户名和密码. 2.服务器验证通过 ...
- cocos creator麻将教程系列(二)—— 达达麻将的底层通讯express框架与socketio
达达麻将网络通讯 目录 达达麻将网络通讯 要点: (1)express框架的基本写法 (2)socket.io的基本原理和使用; (3)creator阅读源码的必杀技巧; (4)一起来看达达麻将的游客 ...
- express 框架之session
一.什么是session? 最近在学习node.js 的express框架,接触到了关于session方面的内容.翻阅了一些的博客,学到了不少东西,发现一篇博文讲的很好,概念内容摘抄如下: Sessi ...
- PCI Express解析——系列文章【2】:PCIe原理分析之——PCI Express线路基础
PCI Express解析--系列文章[2]:PCIe原理分析之--PCI Express线路基础 前文我们了解了一些概述的基本PCIe总线的简单知识点,下面本文从一些基本原理做一些分析 2 PCIe ...
- Computer OS系统基本原理
Computer OS系统基本原理 第一章 绪论(考概念) 什么是OS? o 操作系统是一组控制和管理计算机软硬件资源.合理地对各类作业进行调度以及方便用户使用的程序集合. o 操作系统是位于硬件层( ...
- XGBoost4J-Spark基本原理
XGBoost4J-Spark基本原理 XGBoost4J-Spark是一个项目,旨在通过使XGBoost适应Apache Spark的MLLIB框架,无缝集成XGBoost和Apache Spark ...
- Docker基本原理概述
Docker基本原理概述 Docker是一个用于开发,交付和运行应用程序的开放平台.Docker能够将应用程序与基础架构分开,从而可以快速交付软件.借助Docker,可以以与管理应用程序相同的方式来管 ...
- 多机多卡训练基本原理
多机多卡训练基本原理 在工业实践中,许多较复杂的任务需要使用更强大的模型.强大模型加上海量的训练数据,经常导致模型训练耗时严重.比如在计算机视觉分类任务中,训练一个在ImageNet数据集上精度表现良 ...
最新文章
- mysql clomn_mysql 备份脚本
- (一)面试题:TCP三次握手
- 在WildFly的REST Web服务中与Jackson的双向关系
- 完全二叉树基本操作(不含遍历)
- 请求的内容似乎是脚本,因而将无法有静态文件处理程序来处理(http error 404.17、0x80070032、IIS7)...
- Flutter ScrollController not attached to any scroll views 异常
- iframe缓存无法清空_详解Http缓存机制
- php替换指定函数,PHP替换指定字符函数str_replace()的用法
- 大数据之-Hadoop3.x_MapReduce_outputformat概述---大数据之hadoop3.x工作笔记0120
- SCPPO(二十):系统统一身份认证的改造之路
- datatable相同列合并_使用Power Query合并查询
- L2TP 配置实例——Client-Initiated
- 19-random猜数
- APP抓包,针对 SSLPinning反爬
- java短信接口代码_java调用短信接口代码
- Echarts数据可视化总结
- 真北敏捷 | 明治维新与敏捷:思想、制度和器物
- c++基础复习(2)
- [网鼎杯 2018]Fakebook
- java基于微信小程序的驾校报名预约考试 uniapp小程序