Express
是基于Node.js
平台(建立在Node.js
内置的http模块上),快速、开放、极简的Web开发框架。
中文官网 http://www.expressjs.com.cn/。
Github地址:https://github.com/orgs/expressjs。
Express
核心特性:
npm i express
以上命令会将express
安装在当前目录下的node_modules文件夹下,并且将其依赖的包也一并下载下来
以下几个和express
搭配使用的包:
基本使用步骤:
// 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
方法用于指定变量的值
// 设置 端口
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
对象表示 HTTP请求,包含了请求查询的字符串,参数、内容、HTTP头部等属性。常见属性:
// 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
对象表示 HTTP响应,即在接受到请求时向客户端发送的数据。常见属性:
路由
即路径映射。在Express
中,路由指客户端的请求与服务器处理函数的映射。
Express
中路由是一个单独的组件Express.Router
。
Express
中路由由三部分组成,分别为请求类型、请求URL、处理函数。其格式如下:
app.method(path, handler())
路由匹配过程
// 导入 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
中间件调用流程
注意:
通过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。
https://github.com/expressjs/cookie-parser
res.cookie(name, value[, options])
参数说明
不签名实例
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签名与不签名获取的方式不一样。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)
res.clearCookie(name[, options])
express-session
用于处理请求中的会话。
https://github.com/expressjs/session
session(options)
参数说明:
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
可用于存储或访问会话数据,以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
(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.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'})
})
// 此处的 secret 值必须和jwt 生成时所使用的秘钥相同
// unless 指定了哪些接口无须携带Token访问
app.use(expressJWT({secret: '^123456$'}).unless({path:[/^\/api\//]}))
在访问权限的接口中,可通过req.user对象即可访问 JWT 字符串中解析的内容
// 通过异常中间件来处理JWT解析失败
app.use((err, req, res, next) => {
if(err.name === 'UnauthorizedError') {
// TODO
}
next()
})
multer
是用于处理multipart/form-data
类型的表单数据,主要用于上传文件。(不会处理任何非 multipart/form-data 的数据
)
multer
在解析完请求体后,会向request对象上添加一个body对象和一个file或files对象。body对应表单中提交的文本字段,file或files包含了表单上传的文件。
https://github.com/expressjs/multer
multer(options)
参数说明:
storage
为存储引擎,multer
中具有DiskStorage、MemoryStorage和第三方等引擎。
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
为内层存储引擎(将内容存储在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 |
自定义中间件流程:
自定义中间件解析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
模板可分静态模板和动态模板两类:
Express
中常用的模板引擎:
HTML
的模版引擎:Mustache、HandlebarsJavaScript
的模版引擎:EJS、Underscore.jsCSS
的模版引擎:LESS、SASS模版使用步骤
app.set("view engine", "xxx")
app.set("views", path.resolve(__dirname, "views"))
(表示模板存放在当前目录下views文件夹中)res.render('xx',renderDataObj)
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