Node.js第六篇:Express框架
1.2-什么是Express
基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
Express提供了一系列强大的特性,来帮助我们创建各种web应用。
- 提供了简洁的路由定义方式
- 对获取HTTP请求参数进行了简化处理
- 对模板引擎支持程度高,便于渲染动态的HTML页面
- 提供了中间件机制有效的控制HTTP请求
- 拥有大量第三方中间件对功能进行扩展
原生Node.js和Express框架路由对比:
原生Node.js和Exprees框架获取请求参数对比
1.3-快速入门
安装express框架
命令:npm install express --save
构建第一个基于express框架的web应用
// 导入express包const express = require("express")
// 创建服务器对象
const app = express()
// 监听请求(网站根路径)
app.get("/", (req, res) => {
// 响应内容
// send方法自动检测并设置响应内容类型以及状态码
res.send("Hello Expreess")
})
// 设置端口
app.listen(3000, "localhost")
console.log("服务器启动成功:http://localhost:3000")
第二章:中间件
2.1-认识中间件
什么是中间件
我们开发web应用,核心操作无非就是处理请求和响应。
从请求处理开始直到响应处理结束,才是一个完整的周期。
在请求和响应之间,我们可以通过express提供的一系列方法或第三方模块进行额外的操作。
而中间件就是处理请求和响应之间的一系列方法,这些方法可以接收客户端发送的请求、可以对请求作出响应、也可以将请求继续交给下一个中间件处理。
中间件由两部分组成,中间件方法以及请求处理函数
- 中间件方法由Express提供,负责拦截请求
- 请求处理函数由开发人员提供,负责处理请求。
比如我们用到的路由,其实就是一个中间件(我们用到的get和post方法就是中间件方法)
体验中间件的使用
我们可以针对同一个请求,设置多个中间件进行多次处理。
默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配。
可以调用next方法将请求控制权交给下要给中间件,直到遇到结束请求的中间件。
const express = require("express")const app = express()
// 中间件1处理请求
app.get("/user", (req, res,next) => {
req.name = "Burce"
// 调用next方法,将控制权交给下一个中间件
next()
})
// 中间件2处理请求
app.get("/user", (req, res) => {
res.send(req.name)
})
app.listen(3000, "localhost")
console.log("服务器启动成功:http://localhost:3000/user")
2.2-中间件use方法
use方法使用介绍
app.use方法可以匹配所有的请求方式(不区分get和post),也可以直接传入请求处理函数,接收所有请求
app.use((req,res,next)=>{ console.log("处理请求")
...
next()
})
app.use第一个参数也可以传入请求地址,代表不论什么请求方式,只要是这个请求地址就可以接收这个请求
app.use("请求路径",(req,res,next)=>{ console.log("处理请求")
...
next()
})
代码
const express = require("express")const app = express()
// 【中间件a-处理所有请求】
app.use((req, res, next) => {
console.log("中间件a处理了请求")
next()
})
// 【中间b-处理/user请求-不论是get还是post】
app.use("/user", (req, res, next) => {
console.log("中间件b处理了/user请求")
next()
})
// 【中间c-处理/user请求-get请求】
app.get("/user", (req, res, next) => {
console.log("中间件c处理了/user-get请求")
res.send("ok")
})
// 【中间d-处理/user请求-get请求】
app.get("/list", (req, res, next) => {
console.log("中间件d处理了/list-get请求")
res.send("ok")
})
app.listen(3000)
在浏览器中输入地址http://localhost:3000/user发送请求
请求结果
中间件a处理了请求中间件b处理了/user请求
中间件c处理了/user-get请求
2.3-中间件的实际应用
登录验证
比如登录验证,客户端在访问需要登录的页面时,可以先使用中间件判断用户的登录状态,如果未登录则拦截请求,直接响应,禁止用户进入需要登录的页面。
app.use("/user", (req, res, next) => { // 模拟是否登陆状态
let isLogin = false
if (isLogin) {
next()
} else {
res.send("请先登录")
}
})
app.get("/user", (req, res, next) => {
res.send("欢迎来到user页面")
})
网站维护公告
在所有的路由最上面定义所有请求的中间件,直接为客户端做出响应,网站正在维护中
app.use((req, res, next) => { res.send("服务器正在维护中,截止到2030年")
})
app.use("/user", (req, res, next) => {
let isLogin = true
if (isLogin) {
next()
} else {
res.send("请先登录")
}
})
app.get("/user", (req, res, next) => {
res.send("欢迎来到user页面")
})
自定义404页面
可以把接收所有请求的中间接件定义在路由最后面,当上面的路由不满足时,说明没有匹配的路由,此时可以响应页面不存在。
app.use("/user", (req, res, next) => { let isLogin = true
if (isLogin) {
next()
} else {
res.send("请先登录")
}
})
app.get("/user", (req, res, next) => {
res.send("欢迎来到user页面")
})
app.use((req, res, next) => {
res.status(404).send("你访问的页面被外星人带走了!")
})
2.4-错误处理中间件
使用方式
在程序执行的过程中,不可避免可能会发生一些无法预料的错误,比如数据库连接失败、文件读取失败等。
而错误处理中间件是一个集中处理错误的地方。
app.use((err,req,res,next)=>{ res.status(500).send("服务器内部错误")
})
对于异步错误,调用next方法,可以将错误信息通过参数的方式传递给next()方法,即可触发错误处理中间件。
app.get("/file",(req,res,next)=>{ fs.readFile("01.txt","utf-8",(err,data)=>{
if(err) {
next(err)
}else {
res.send(data)
}
})
})
代码演示
const express = require("express")const fs = require("fs")
const app = express()
app.use("/user", (req, res, next) => {
throw new Error("未知错误")
})
app.get("/file", (req, res, next) => {
fs.readFile("01.txt", "utf-8", (err, data) => {
if (err) {
next(err)
} else {
res.send(data)
}
})
})
app.use((err, req, res, next) => {
if (err) {
res.status(500).send(err.message)
}
})
app.listen(3000)
2.5-捕获错误
try catch介绍
在node.js中,异步ApI的错误信息都是通过回调函数获取的,支持Promise对象的异步API发送错误可以通过catch方法捕获。
异步函数执行如果发生错误要如何捕获错误呢?
try catch
可以捕获异步函数以及其他同步代码在执行过程中发生的错误,但是不能捕获其他类型的API发送的错误。
代码
const express = require("express")const fs = require("fs")
/*默认情况下,fs.readFile方法返回的不是promise对象,所以无法使用await关键字,可以通过util模块下的promisify方法改造其他方法,使其可以使用await关键字 */
const promisify = require("util").promisify
fs.readFile = promisify(fs.readFile)
const app = express()
app.get("/file", async (req, res, next) => {
try {
const result = await fs.readFile("01.txt", "utf-8")
res.send(result)
} catch (ex) { // 捕获错误
next(ex)
}
})
app.use((err, req, res, next) => {
if (err) {
res.status(500).send(err.message)
}
})
app.listen(3000)
第三章: 模块化路由
3.1-为什么要构建模块化路由
在项目实际开发当中,我们的项目是要根据业务划分模块并且多人协同开发的,若把所有的路由都集中在一个程序文件中处理,则难以实现多人协同开发且难以维护。
3.2-如何实现模块化路由
实现方式
首先根据模块的划分,为每个模块创建独立的路由程序文件;
其次在模块中通过express的Router方法
创建路由对象;
然后在模块中使用路由对象处理指定的请求;
最后,在程序入口文件中导入各个路由模块,并使用use方法挂载到web应用中。
app.use("路由名称",路由对象)
发送请求:/路由名称/请求地址
代码演示
路由模块home.js
const express = require("express")const home = express.Router();
home.get("/index", (req, res) => {
res.send("欢迎来到home首页")
})
home.get("/list", (req, res) => {
res.send("欢迎来到home列表页")
})
module.exports = home
路由模块admin.js
const express = require("express")const admin = express.Router();
admin.get("/index", (req, res) => {
res.send("欢迎来到admin首页")
})
admin.get("/list", (req, res) => {
res.send("欢迎来到admin列表页")
})
module.exports = admin
web应用程序入口app.js
const express = require("express")// 导入home路由模块
const home = require("./router/home")
// 导入admin路由模块
const admin = require("./router/admin")
const app = express()
// 把home路由模块挂载到web应用中,监听/home路径下的请求
app.use("/home", home)
// 把admin路由模块挂载到web应用中,监听/admin路径下的请求
app.use("/admin", admin)
app.listen(80)
访问:例如http://localhost/admin/list
结果:欢迎来到admin列表页
第四章:请求参数
4.1-获取get请求参数
获取方式
req.query
,返回值是一个对象。
express框架内部将请求参数转换为对象。
代码演示
const express = require("express")const app = express()
app.get("/index", (req, res) => {
res.send(req.query)
})
app.listen(80)
请求:http://localhost/index?word=程序媛&gender=女
结果:{"word":"程序媛","gender":"女"}
4.2-获取post请求参数
获取方式
安装第三方模块:npm install body-parser
导入并配置body-parser模块:
const bodyParser = require("body-parser")// 拦截所有请求
// extend: false 表示方法内部使用querystring模块处理请求参数格式
// extend: true 表示方法内部使用第三方模块qs处理请求参数格式
app.use(bodyParser.urlencoded({extend: false}))
获取参数:req.body
返回一个对象
代码演示
form表单
<form action="http://localhost/add" method="post"> <p>账号:<input type="text" name="account"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form
服务端程序
const express = require("express")// 导入body-parser模块
const bodyParser = require("body-parser")
const app = express()
// 配置bodyParser
app.use(bodyParser.urlencoded({extended:false}))
app.post("/add", (req, res) => {
// 获取post请求参数
res.send(req.body)
})
app.listen(80)
返回结果:{"account":"admin","pwd":"123456"}
4.3-Express中的路由参数
路由参数的定义和使用
请求路径格式: /路径名称/:参数1名称/:参数2名
调用方式:http://localhost/find/值1/值2
代码演示
const express = require("express")const app = express()
app.get("/find/:id", (req, res) => {
res.send(req.params)
})
// 测试:http://localhost/find/1
app.get("/find/:id/:name", (req, res) => {
res.send(req.params)
})
// 测试:http://localhost/find/1/admin
app.get("/find", (req, res) => {
res.send("find")
})
// 测试:http://localhost/find
app.listen(80)
第五章:静态资源的处理
通过Express内置的express.static可以方便地托管静态文件,例如img、css、javascript文件等。
配置方式
app.use("虚拟路径",express.static("静态资源真实路径"))
虚拟路径可选
代码演示
const express = require("express")const path = require("path")
const app = express()
const statiPath = path.join(__dirname,"./public")
// app.use(express.static(statiPath))
// 测试:http://localhost/index.html
app.use("/static", express.static(statiPath))
// 测试:http://localhost/static/index.html
app.listen(80)
第六章:Express中使用模板引擎
为了使art-template模板引擎能够更好的和Express框架结合,模板引擎官方在原art-template
模板引擎的基础上封装了express-art-template
。
安装模板引擎
安装命令: npm install art-template express-art-template
代码演示
app.js
const express = require("express")const path = require("path")
const app = express()
// 多个模板使用公共数据
// app.locals.key = value
app.locals.users = [
{name:"Bruce",age: 10},
{name:"Andy",age: 20}
]
// 配置框架使用哪个模板引擎,以及处理后缀为什么的模板
app.engine("art", require("express-art-template"))
// 设置模板存放的目录
app.set("views", path.join(__dirname, "views"))
// 设置模板的默认后缀
app.set("view engine", "art")
app.get("/index", (req, res) => {
// index 模板名称 data模板中需要的数据
res.render("index", { data: "首页的数据" })
// render方法会自动匹配并响应
})
app.get("/list", (req, res) => {
res.render("list",{data:"列表页的数据"})
})
app.listen(80)
list.art
{{data}}<ol>
{{each users}}
<li>
第{{$index+1}}个用户
<ul>
<li>name:{{$value.name}}</li>
<li>age:{{$value.age}}</li>
</ul>
</li>
{{/each}}
</ol>
index.art
{{data}}<ol>
{{each users}}
<li>
第{{$index+1}}个用户
<ul>
<li>name:{{$value.name}}</li>
<li>age:{{$value.age}}</li>
</ul>
</li>
{{/each}}
</ol>
第七章:cookie和Session
7.1-概述
众所周知,Http协议是无状态的,也就意味着,针对浏览器与服务器之间的请求和响应(也叫会话),当两者之间的会话结束时,服务器端并不会记忆客户端(浏览器)曾经访问过。
但是,在实际应用程序开发中,有些业务需要浏览器和服务器之间能够保持会话。比如常见的登录业务,在同一个浏览器下,当用户第一次登录成功并进入首页时,下次再使用同一个浏览器访问首页时,则不需要再登录。而要实现下次访问不再登录时,需要让服务端能够识别曾经访问过它的浏览器,这就需要会话跟踪技术来实现。分别是cookie
和session
。
7.2-cookie
cookie:浏览器在电脑硬盘中开辟的一块空间,主要提供服务端存储数据。
- cookie中的数据是以域名的形式进行区分的。
- cookie中的数据是有过期时间的,超过时间数据会被浏览器自动删除。
- cookie中的数据会随着请求被自动发送到服务器端。
7.3-session
实际上就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识。
session依赖于cookie,比如我们要实现一个邮箱和密码登录会话跟踪的功能。其实现过程如下图:
7.4-express-session
在express框架中,可以使用第三方包express-session
操作session
具体代码如下:实现一个记录用户使用某个终端访问该网站的次数
// 导入express模块const express = require("express")
// 导入express-session模块
const session = require("express-session")
// 创建服务对象
const app = express();
// session的名称
let identityKey = "skey";
//使用session
app.use(session({
name: identityKey,
secret: "appkey", // 用来对session id相关的cookie进行签名
// store: new FileStore(), // 本地存储session(文本文件,也可以选择其他store,比如redis的)
saveUninitialized: false, // 是否自动保存未初始化的会话,建议false
resave: false, // 是否每次都重新保存会话,建议false
cookie: {
maxAge: 10 * 1000 // 有效期,单位是毫秒
}
}));
// session存储数据
app.get("/", (req, res) => {
// 判断是否是第一次访问
if (req.session.count) {
req.session.count += 1;
} else {
req.session.count = 1
}
res.send("欢迎访问,您是第" + req.session.count + "此访问我们")
})
//清除session
app.get("/logout", function(req, res, next){
// 备注:这里用的 session-file-store 在destroy 方法里,并没有销毁cookie
// 所以客户端的 cookie 还是存在,导致的问题 --> 退出登陆后,服务端检测到cookie
// 然后去查找对应的 session 文件,报错
// session-file-store 本身的bug
req.session.destroy(function(err) {
if(err){
res.json({ret_code: 2, ret_msg: "退出登录失败"});
return;
}
// req.session.loginUser = null;
res.clearCookie(identityKey);
res.send("ok")
});
});
app.listen(80)
以上是 Node.js第六篇:Express框架 的全部内容, 来源链接: utcz.com/z/516363.html