[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)

```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 基礎
- React + ts
- 樣式設計
- 組件測試
- 圖標解決方案
- Storybook 的使用
- Input 組件
- 在線 mock server
- 打包與發布
- Algorithm
- 排序算法及常見問題
- 劍指 offer
- 動態規劃
- DataStruct
- 概述
- 樹
- 鏈表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 課程實戰記錄
- 服務器
- 操作系統基礎知識
- Linux
- Nginx
- redis
- node.js
- 基礎及原生模塊
- express框架
- node.js操作數據庫
- 《深入淺出 node.js》筆記
- 前半部分
- 后半部分
- 數據庫
- SQL
- 面試題收集
- 智力題
- 面試題精選1
- 面試題精選2
- 問答篇
- 2025面試題收集
- Other
- markdown 書寫
- Git
- LaTex 常用命令
- Bugs