[TOC]
# express简介
Express 对原生 node.js 做了进一步的封装,使用起来更为方便,代码更为简洁。 Express 是一个自身功能极简,完全由路由和中间件构成的一个 web 开发框架。从本质上来说,一个 Express 应用就是在调用各种中间件。
# Hello world示例
```js
const express = require('express')
const app = express()
app.get('/', function(req, res) {
res.send('hello world')
})
app.listen(3000)
```
一般让 express() 方法返回一个名为 app 的对象,这个对象预设了一系列的方法
API 中分为 Properties,Events,Methods
app.listen 方法实际上是创建了一个 HTTP 服务,如下
```js
app.listen = function () {
let server = http.createServer(this)
return server.listen.apply(server, arguments)
}
```
其可以接受一个回调函数:
```javaScript
// 回调函数打印监听的地址和端口号
const server = app.listen(3000, () => {
const host = server.address().address
const port = server.address().port
console.log('server is listening at http://%s:%s', host, port)
})
```
# middleware(中间件)
中间件的行为类似 Java 中过滤器的工作原理,就是在进入具体的业务处理之前,先让过滤器处理,比如对于每个请求我们一般都要解析 cookie,querystring 什么的,那么就设计对应的中间件处理完成后存储在上下文中(req 和 res,Koa2 合并为一个 context)
![](https://box.kancloud.cn/22d3c8400e5948030aa16412085e73c0_901x501.png)
```js
// 模拟中间件的实现
const http = require('http')
const slice = Array.prototype.slice
class LikeExpress {
constructor() {
// 存放中间件的列表
this.routes = {
all: [], // 存放 app.use 注册的中间件
get: [], // 存放 app.get 注册的中间件
post: []
}
}
// 内部实现注册的方法
register(path) {
const info = {}
if (typeof path === 'string') { // 字符串 - 路由
info.path = path
// 从第二个参数开始,转换为数组,存入stack
info.stack = slice.call(arguments, 1) // 取出剩余的参数
} else { // 没有显式地传入路由则默认是根路由
info.path = '/' // 省略第一个参数 -> 根目录
// 从第一个参数开始,转换为数组,存入stack
info.stack = slice.call(arguments, 0)
}
// { path: '', stack: [middleware, ...] }
return info
}
use() {
const info = this.register.apply(this, arguments) // 把当前函数的所有参数传入
this.routes.all.push(info)
}
get() {
const info = this.register.apply(this, arguments) // 把当前函数的所有参数传入
this.routes.get.push(info)
}
post() {
const info = this.register.apply(this, arguments) // 把当前函数的所有参数传入
this.routes.post.push(info)
}
match(method, url) {
let stack = [] // resultList
if (url === '/favicon.ico') { // 小图标无视
return stack
}
// 获取 routes
let curRoutes = []
curRoutes = curRoutes.concat(this.routes.all)
curRoutes = curRoutes.concat(this.routes[method])
curRoutes.forEach(routeInfo => {
if (url.indexOf(routeInfo.path === 0)) {
// url === '/api/get-cookie' 且 routeInfo.path === '/'
// url === '/api/get-cookie' 且 routeInfo.path === '/api'
// url === '/api/get-cookie' 且 routeInfo.path === '/api/get-cookie'
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
// 核心的 next 机制
handle(req, res, stack) {
const next = () => {
// 拿到第一个匹配的中间件
const middleware = stack.shift()
if (middleware) {
// 执行中间件函数
middleware(req, res, next)
}
}
next()
}
callback() {
return (req, res) => {
// 自己定义 res.json 方法
res.json = data => {
res.setHeader('Content-Type', 'application/json')
res.end(
JSON.stringify(data)
)
}
// 获取 url 和 method :通过这两个来获得需要经过的中间件
const url = req.url
const method = req.method.toLowerCase()
// match 函数匹配可用的中间件列表
const resultList = this.match(url, method)
this.handle(req, res, resultList)
}
}
listen(...args) {
const server = http.createServer(this.callback)
server.listen(...args)
}
}
// 工厂函数
module.exports = () => {
return new LikeExpress()
}
```
# 常用的中间件及其功能
## 解析 request 对象
- `req.body`:使用 body-parser 中间件帮我们处理后可以直接通过 req.body 获取 POST请求的实体数据(axios 的 data 选项)
```js
var app = require('express')();
var bodyParser = require('body-parser');
var multer = require('multer'); // v1.0.5
var upload = multer(); // for parsing multipart/form-data
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.post('/profile', upload.array(), function (req, res, next) {
console.log(req.body);
res.json(req.body);
});
```
现在 body-parser 已经成为内置中间件了,我们使用 express 脚手架构建([https://www.jianshu.com/p/a77b806b0d14](https://www.jianshu.com/p/a77b806b0d14))的项目可以看到如下两行(注释我写的):
```js
// built-in middleware
// 基于 body-parser POST 请求有 4 种数据格式,因此需要与下面一个中间件结合使用
app.use(express.json())
// built-in middleware
// Content-Type: x-www-... 用表单提交时的 POST 数据格式 解析结果会存入 req.body 和 JSON 格式数据一样
app.use(express.urlencoded({ extended: false }))
```
- `req.cookies`:使用了 cookie-parser 中间件后可以直接通过 req.cookies 来获取 cookies 信息
```js
// Cookie: name=tj
req.cookies.name
// => "tj"
```
- `req.query`:可直接通过 req.query 获取 querystring,如果没有返回空对象 {}
```js
// GET /search?q=tobi+ferret
req.query.q
// => "tobi ferret"
// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
req.query.order
// => "desc"
req.query.shoe.color
// => "blue"
req.query.shoe.type
// => "converse"
```
- `req.path`:Contains the path part of the request URL.
```js
// example.com/users?sort=desc
req.path
// => "/users"
```
- `req.hostname`:Contains the hostname derived from the`Host`HTTP header.
```js
// Host: "example.com:3000"
req.hostname
// => "example.com"
```
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令