概述
Express
是基于Node.js
平台(建立在Node.js
内置的http模块上),快速、开放、极简的Web开发框架。
中文官网 http://www.expressjs.com.cn/。
Github地址:https://github.com/orgs/expressjs。
Express
核心特性:
- 可设置中间件来响应 HTTP 请求
- 定义了路由表用于执行不同的 HTTP 请求
- 可通过向模板传递参数来动态渲染 HTML 页面
安装
npm i express
以上命令会将express
安装在当前目录下的node_modules文件夹下,并且将其依赖的包也一并下载下来
以下几个和express
搭配使用的包:
- body-parser 用于处理 JSON、Raw、Text和URL中的请求数据
- cookie-parser 用于处理Cookie
- multer 用于处理**enctyoe=“multipart/form-data””**的表单数据
基本使用
基本使用步骤:
- 导入 express 模块
- 创建 express 实例
- 创建并启动HTTP服务
- 绑定请求事件
// 1. 导入 express 包
const express = require('express')
// 2. 创建 express 实例
const app = express()
// 3. 启动服务
app.listen(80, () => {
console.log("Express server is starting ...")
})
// 4. 绑定请求事件
app.get("/", (req, res) => {
console.log("请求进来了 >>> " + req.url)
res.end("Hello Node.js")
})
set 方法
set
方法用于指定变量的值
// 设置 端口
app.set("port", process.env.PORT)
// 设定views变量,意为视图存放的目录
app.set('views', path.join(__dirname, 'views'));
// 设定view engine变量,意为网页模板引擎
app.set('view engine', 'jade');
请求和响应
Express
处理请求中回调函数的参数:request和response对象来处理请求和响应。
request 对象
request
对象表示 HTTP请求,包含了请求查询的字符串,参数、内容、HTTP头部等属性。常见属性:
- request.app 当callback为外部文件时,用其访问express实例
- request.baseUrl 获取当前的 URL 路径
- request.method 获取请求方法
- request.body 获取请求体内容
- request.cookie 获取 Cookie 内容
- request.hostname 获取主机名
- request.ip 获取IP
- request.originalUrl 获取原始请求 URL
- request.params 获取请求参数(动态匹配的参数)
- request.path 获取请求路径
- request.protocol 获取请求协议
- request.query 获取URL的查询参数
- request.route 获取请求匹配的路由
- request.get() 获取指定的请求头
- request.is() 判断请求头Content-Type的MIME类型
// http://domain:port/x1/x2/wz?age=18
request.path // /x1/x2/wz
request.params // wz
request.query // age
// 引入express 模块
const express = require('express')
// 创建 实例
const app = express()
// 启动服务
app.listen(80, () => {
console.log("Server is starting ...")
})
// 绑定 get 请求事件
app.get('/user', (req, res) => {
// req.protocol 获取请求协议
console.log("protocol >>> ", req.protocol)
// req.method 获取请求方法
console.log("method >>> ", req.method)
// req.hostname 获取主机名
console.log("hostname >>> ", req.hostname)
// req.ip 获取请求 IP
console.log("ip >>> ", req.ip)
// req.originalUrl 获取请求原始路径
console.log("originalUrl >>> ", req.originalUrl)
// req.path 获取请求路径
console.log("path >>> ", req.path)
// req.route 获取请求路由
console.log("route >>> ", req.route)
// req.params 获取请求参数
console.log("params >>> ", req.params)
// req.query 获取请求查询参数
console.log("query >>> ", req.query)
// req.body 获取请求体
console.log("body >>> ", req.body)
res.end("GET")
})
// 绑定 post 请求事件
app.post('/user', (req, res) => {
// req.protocol 获取请求协议
console.log("protocol >>> ", req.protocol)
// req.method 获取请求方法
console.log("method >>> ", req.method)
// req.hostname 获取主机名
console.log("hostname >>> ", req.hostname)
// req.ip 获取请求 IP
console.log("ip >>> ", req.ip)
// req.originalUrl 获取请求原始路径
console.log("originalUrl >>> ", req.originalUrl)
// req.path 获取请求路径
console.log("path >>> ", req.path)
// req.route 获取请求路由
console.log("route >>> ", req.route)
// req.params 获取请求参数
console.log("params >>> ", req.params)
// req.query 获取请求查询参数
console.log("query >>> ", req.query)
// req.body 获取请求体
console.log("body >>> ", req.body)
res.end("POST")
})
response 对象
response
对象表示 HTTP响应,即在接受到请求时向客户端发送的数据。常见属性:
- response.app 当callback为外部文件时,用其访问express实例
- response.cookie(name, value[, options]) 设置Cookie信息
- response.clearCookie() 清空Cookie
- response.download() 传送指定的文件
- response.get() 获取指定的HTTP头信息
- response.set(name, value) 设置响应头(Header)
- response.json() 响应JSON格式的数据
- response.render(view[, locals], callback) 渲染网页模版
- response.send() 发送响应
- response.sendFile(path[, options][, fn]) 传送文件
- response.status() 设置 HTTP 状态码
- response.type() 设置 Content-Type的 MIME类型
- response.redirect() 设置重定向
路由
路由
即路径映射。在Express
中,路由指客户端的请求与服务器处理函数的映射。
Express
中路由是一个单独的组件Express.Router
。
Express
中路由由三部分组成,分别为请求类型、请求URL、处理函数。其格式如下:
app.method(path, handler())
路由匹配过程
- 请求到达服务器时,先经过路由的匹配,匹配成功了,才会调用对应的处理函数
- 在匹配时,按照定义的顺序依次匹配,仅当请求类型和请求URL同时匹配成功了,才会调用对应的处理函数
// 导入 express 模块
const express = require('express')
// 创建 express 实例
const app = express()
// 创建路由实例
const router = express.Router()
// 挂载路由
router.get('/user', (req, res) => {
res.send("express router")
})
// 注册路由
app.use('/api', router)
// 启动服务
app.listen(80, () => {
console.log("Server is starting ...")
})
// 访问路径 http://domain:port/api/user
中间件
中间件(Middleware
)指业务流程的中间处理环节。其是一个函数,包含了request、respoonse、next三个参数,其中 next() 把流转交给下一个中间件或路由。
Express
中间件调用流程
注意:
- 在注册路由之前注册中间件(错误中间件除外)
- 多个中间件共享request和response对象
- next() 函数后不能再写逻辑代码
全局中间件
通过app.use()
注册的中间件为全局中间件
const express = require('express')
const app = express()
// 注册全局中间件
app.use((req, res, next) => {
console.log("中间件A")
})
// 注册全局中间件
app.use((req, res, next) => {
console.log("中间件B")
})
app.get('/user', (req, res) => {
res.send("ok")
})
app.listen(8888)
局部中间件
const express = require('express')
const app = express()
// 定义中间件
const mw1 = (req, res, next) => {
console.log("中间件A")
}
// 注册全局中间件
const mw2 = (req, res, next) => {
console.log("中间件B")
}
app.get('/user', mw1, mw2, (req, res) => {
res.send("ok")
})
app.post('/user', [mw1, mw2], (req, res) => {
res.send("ok")
})
app.listen(8888)
中间件分类
中间件按照作用可划分为三类:应用级别中间件、路由级别中间件、错误级别中间件。
应用级别中间件
通过app.use()
或app.method()
注册,即绑定到app实例上的中间件即为应用级别中间件。(其中method为get
、post
、put
、delete
等请求方法)
const express = require('express')
const app = express()
// 注册路由
app.use('/', (req, res, next) => {
next()
})
路由级别中间件
通过router.use()
注册,即绑定到router实例上的中间件即为路由级别中间件。
const express = require('express')
const app = express()
const router = express.Router()
// 路由上注册中间件
router.use((req, res, next) => {
next()
})
// 注册路由
app.use('/', router)
错误级别中间件
错误级别中间件用来捕获整个项目中发生的异常,从而防止项目异常崩溃。
错误级别中间件的处理函数中必须有4个形参,即(error, request, response, next)
错误级别中间件必须注册在所有路由之后
const express = require('express')
const app = express()
// 请求处理 ...
// 注册错误中间件
app.use((err, req, res, next) => {
next()
})
内置中间件
Express
中内置了多个中间件,极大的提高了 Express 项目的开发效率。常见内置中间件:
-
express.static 快速托管静态资源
express.static(root[, options])
-
express.json 解析JSON格式的请求体数据
-
express.urlencoded 解析 url-encoded 格式的请求体数据
// 快速托管静态资源
app.use(express.static(path))
// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())
// 通过 express.urlencoded() 这个中间件,来解析表单中的 url-encoded 格式的数据
app.use(express.urlencoded({ extended: false }))
第三方中间件
cookie-parser
cookie-parser
用于处理请求中的Cookie。
https://github.com/expressjs/cookie-parser
设置Cookie
res.cookie(name, value[, options])
参数说明
- name cookie名称
- value cookie值
- options 配置参数
- domain 域名。默认为当前域名
- expires 失效时间。未设置或0,表示浏览器关闭后即失效
- maxAge 最大失效时间(指从当前时间开始多久后失效),单位毫秒
- secure 为 true时,cookie 在 http 失效,https 生效
- path cookie在什么路径下有效。默认为**/**
- httpOnly 只能被访问,防止 XSS攻击
- signed 是否签名。默认指为false
不签名实例
const express = require('express')
const cookieParser = require('cookie-parser')
// 创建 app 实例
const app = express()
// 注册 Cookie中间件
app.use(cookieParse())
app.get('/setCookie', (req, res) => {
res.cookie('name', '张三', {
maxAge: 10000
})
res.send('cookie set success!')
})
app.listen(8888)
签名实例
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser('^123$')) // ^123$ 为签名秘钥
app.get('setCookie', (req, res) => {
// 将cookie的name 进行签名
res.cookie("name", "张三", {maxAge: 100000, signed: true})
})
获取Cookie
注意:
Cookie签名与不签名获取的方式不一样。req.cookies
获取不签名的cookie;req.signedCookies
获取签名的cookie。
不签名实例
const express = require('express')
const cookieParser = require('cookie-parser')
// 创建 app 实例
const app = express()
// 注册 Cookie中间件
app.use(cookieParser()) //
app.get('/getCookie', (req, res) => {
console.log(req.cookies)
res.send("cookie got")
})
app.listen(8888)
签名实例
const express = require('express')
const cookieParser = require('cookie-parser')
// 创建 app 实例
const app = express()
// 注册 Cookie中间件
app.use(cookieParser('^123$')) // ^123$ 为签名秘钥
app.get('/getCookie', (req, res) => {
console.log(req.signedCookies)
res.send("cookie got")
})
app.listen(8888)
删除Cookie
res.clearCookie(name[, options])
express-session
express-session
用于处理请求中的会话。
https://github.com/expressjs/session
配置 session
session(options)
参数说明:
- options 配置参数
- cookie cookie设置
- genid sessionid算法。默认为uid-safe库自动生成id
- name 会话名称。默认为 connect.sid
- secret 会话签名秘钥
- store 会话存储方式。默认为内存
- resave 是否强制保存会话,及时未被修改也被保存。默认为true
- saveUninitialized 强制将未初始化的会话保存至存储中。(会话是新的且未被修改即为未初始化)
- unset 是否保存会话。默认为keep,不保存可设置为destory
const express = require('express')
const session = require('express-session')
const app = express()
app.use(session({
name: "session-cookie",
secret: "^123456$", // 会话签名秘钥
cookie: {
maxAge: 2 * 60 * 60 * 1000
}
}))
req.session
req.session
可用于存储或访问会话数据,以JSON的形式序列化。
const express = require('express')
const session = require('express-session')
// 创建服务实例
const app = express()
// 配置session,并注册session中间件
app.use(session({
name: "express",
secret: "^123456$",
resave: false,
saveUninitialized: true
}))
app.get('/setSession', (req, res) => {
// 存储会话
req.session.name = "李四"
res.send("set session success")
})
app.get('/getSession', (req, res) => {
// 获取会话
console.log(req.session)
res.send("session got")
})
// 启动服务
app.listen(8888)
属性
属性 | 说明 |
---|---|
req.session.id | 会话ID |
req.session.sessionID | 会话ID |
req.session.cookie | 获取会话中的 cookie 对象, 而后可对其修改 |
req.session.cookie.maxAge | 会话有效剩余时长 |
req.session.cookie.originalMaxAge | 返回会话 cookie 的原始 maxAge, 以毫秒为单位 |
方法
方法 | 说明 |
---|---|
req.session.regenerate(callback) | 重新生成会话 |
req.session.destroy(callback) | 销毁会话并取消设置 req.session 属性 |
req.session.reload(callback) | 从存储重新加载会话数据并重新填充 req.session 对象 |
req.session.save(callback) | 讲会话保存至 store,用内存中的内容替换 store上的内容 |
req.session.touch() | 更新 .maxAge属性 |
JWT
JWT
(JSON Web Token)是由三部分组成:Header、Payload(真正的用户信息,加密后的字符串)、Signature。
JWT
工作原理:用户的信息以Token的字符串的形式,保存在客户端中。用户每次请求,将Token存放在请求头Authorization上,服务器拿到该值后进行解析处理。
Express
中jsonwebtoken
模块用于生成JWT字符串,express-jwt
用于将JWT字符串还原成JSON对象。
使用
- 安装模块
npm install jsonwebtoken express-jwt
- 引入模块
const jwt = requre('jsonwebtoken') const expressJWT = require('express-jwt')
- 生成 JWT 字符串
jwt.sign(payload, secret[, options[, callback]])
payload 存储的对象
secret 签名秘钥
options 配置参数。常见有 expiresIn(过期时间)、algorithm(签名算法)
callback 回调函数app.post('/api/login', (req, res) => { let token = jwt.sign({username: username}, '^123456$', {expireIn: '2h'}) })
- 还原 JWT 字符串
// 此处的 secret 值必须和jwt 生成时所使用的秘钥相同 // unless 指定了哪些接口无须携带Token访问 app.use(expressJWT({secret: '^123456$'}).unless({path:[/^\/api\//]}))
- 获取 JWT 信息
在访问权限的接口中,可通过req.user对象即可访问 JWT 字符串中解析的内容
- 捕获 JWT 异常
// 通过异常中间件来处理JWT解析失败 app.use((err, req, res, next) => { if(err.name === 'UnauthorizedError') { // TODO } next() })
multer
multer
是用于处理multipart/form-data
类型的表单数据,主要用于上传文件。(不会处理任何非 multipart/form-data 的数据
)
multer
在解析完请求体后,会向request对象上添加一个body对象和一个file或files对象。body对应表单中提交的文本字段,file或files包含了表单上传的文件。
https://github.com/expressjs/multer
multer(options)
参数说明:
- options 参数配置
- dest / storage 上传文件存放目录。
- fileFilter 文件过滤器
- limits 限制上传文件 (可有效防止Dos攻击)
- fieldNameSize field名字最大长度。默认为 100 bytes
- fieldSize field指最大长度。默认为1MB
- fields 非文件field的最大数量。默认为无限
- fileSize 文件最大长度,单位字节。默认为无限
- files 文件最大数量。默认为无限
- parts part传输的最大数量(field + file)。默认为无限
- headerPairs 键值对最大组数。默认为2000
- preservePath 保存包含文件名的完整路径
storage
storage
为存储引擎,multer
中具有DiskStorage、MemoryStorage和第三方等引擎。
DiskStorage
DiskStorage
为磁盘存储引擎,其有两个选项可用:destination和filename。
destination 用来确定上传的文件存放的位置。可提供一个 string或function。若没有设置则使用操作系统默认的临时文件夹。
注意:
若destination 是一个function,则需用手动创建文件夹;若destination 是一个string,multer 会自动创建。
filename用来确定文件夹中文件名。若未设置该参数,则文件将设置一个随机文件名且没有后缀名。
const storage = multer.DiskStorage({
distination: function(req, file, cb) {
cb(null, '/xxx/xxx')
}
filename: function(req, file, cb) {
cb(null, file.fieldname + "_" + Date.now())
}
})
const upload = multer({storage: storage})
MemoryStorage
MemoryStorage
为内层存储引擎(将内容存储在Buffer中)
const storage = multer.memoryStorage()
const upload = multer({storage: storage})
注意:
当使用内层存储,上传文件非常大,或上传文件非常多时,可能会导致内层溢出。
方法
multer.single(fieldname)
multer.signle()
接受一个以filename命名的文件,文件保存至request.file中
multer.array(fieldname[, maxCount])
multer.array()
接受一个以fieldname命名的文件数组,可配置maxCount来限制上传文件数量,文件保存至request.files中
multer.fields(fields)
multer.fields()
接受fileds的混合文件,文件保存至request.files中
multer.none()
multer.none()
只接受文本域,和multer.fields([])
效果一样。若该模式有文件上传,则抛出LIMIT_UNEXPECTED_FILE
multer.any()
multer.any()
接受一切上传的文件。文件保存至request.files中
const multer = require('multer')
// 存储设置
const storage = multer.DiskStorage({
distination: function(req, file, cp) {
cp(null, '/xxx/xx')
}
filename: function(req, file, cp)
})
const upload = multer({storage:storage})
app.post('/upload/photo', upload.single('avatar'), function (req, res) {
// req.file 是 `avatar` 文件的信息
// req.body 将具有文本域数据,如果存在的话
})
app.post('/upload/file', upload.array('file', 3), function (req, res) {
// req.files 是 `file` 文件组的信息
// req.body 将具有文本域数据,如果存在的话
})
app.post('/upload', upload.fields([{name: 'avatar', maxCount: 1},{name: 'file', maxCount: 3}]), function (req, res) {
// req.files 是一个对象 (String -> Array) 键是文件名,值是文件数组
// req.files['avatar'][0] -> File
// req.files['file'] -> Array
// req.body 将具有文本域数据,如果存在的话
})
文件属性
属性 | 说明 |
---|---|
fieldname | 表单定义的名称 |
originalname | 文件原始名称 |
encoding | 文件编码 |
mimetype | 文件的 MIME 类型 |
size | 文件大小 |
distination | 文件保存路径 |
filename | 保存至 distination 中的文件名 |
path | 已上传文件的完整路径 |
buffer | 存放整个文件的 Buffer |
自定义中间件
自定义中间件流程:
- 定义中间件
- 监听request对象的 data 事件
- 监听 request 对象的 end 事件
- 解析请求参数
- 封装模块
自定义中间件解析POST提交的数据
// querything 是 Node.js的内置模块
const qs = require('querything')
// 定义中间件
const bodyParser = (req, res, next) => {
let str = ''
// 监听 req 的 data 事件
req.on('data', (chunk) => {
str += chunk
})
req.on('end', () => {
// 解析数据,并将数据放在 req 的 body 中,供下游访问
req.body = qs.parse(str)
next()
})
}
module.exports = bodyParser
模板
Express
模板是用于渲染视图的文件,可以包含HTML、CSS、JavaScript等内容,用于构建 Web应用程序的图形界面。
使用Express
模板可以快速、方便地创建Web应用程序,并可轻松地将动态数据注入到模板中,以便呈现动态效果。常见的模版引擎有:EJS、Pug、Handlebars 等。
分类
Express
模板可分静态模板和动态模板两类:
- 静态模板 预先定义好的 HTML 文件,可通过路由直接呈现
- 动态模板 通过模版引擎加载动态数据来生成动态内容
Express
中常用的模板引擎:
- 基于
HTML
的模版引擎:Mustache、Handlebars - 基于
JavaScript
的模版引擎:EJS、Underscore.js - 基于
CSS
的模版引擎:LESS、SASS
使用
模版使用步骤
- 下载模板包
- 配置模版引擎
app.set("view engine", "xxx")
- 配置模板路径
app.set("views", path.resolve(__dirname, "views"))
(表示模板存放在当前目录下views文件夹中) - 在请求响应中设置渲染
res.render('xx',renderDataObj)
express-generator
express-generator
是 快速创建 express 项目生成器工具。
使用
## 1. 全局安装 express-generator
npm i -g express-generator
## 2. 创建项目
#### 快速创建 [project_name[ 的项目,并且使用默认的 jade 模板引擎
express [project_name]
#### 快速创建 [project_name[ 的项目,并且使用指定的 ejs 模板引擎
express [project_name] --view=ejs
## 3.进入到项目根目录下执行 npm install
npm install
## 4. 启动项目
#### npm 命令
npm run start 或 npm start
#### node 命令
node ./bin/www
## 5.访问 express-generator生成的项目服务默认端口为 3000