express 框架
文章目录
![Express](https://img-blog.csdnimg.cn/direct/b5ae5717cf4f4884a9f0f1c1f9a15550.png#pic_center)
一、express 介绍
express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架(Express 官方地址)
简单的来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
二、express 使用
2.1 express 下载
express 本身是一个 npm 包,所以可以通过 npm 安装
npm init
npm i express
2.2 express 初体验
操作步骤如下:
-
创建 JS 文件,写入如下代码:
// 1.导入 express const express = require('express') // 2.创建应用对象 const app = express() // 3.创建路由 app.get('/home', (req, res) => { res.end('<h1>hello express</h1>') }) // 4.监听端口 启动服务 app.listen(3000, () => { console.log('服务已经启动,端口 3000 正在监听中...') })
-
命令行下执行该脚本
node <文件名> # 或者 nodemon <文件名>
-
然后在浏览器中就可以访问
http://127.0.0.1:3000/home
🆗
三、express 路由
3.1 什么是路由
官方定义:路由确定了应用程序如何响应客户端对特定端点的请求
3.2 路由的使用
一个路由的组成由 请求方法,路径 和 回调函数 组成
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
app.<method>(path, callback)
代码示例:
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 创建 get 路由
app.get('/home', (req, res) => {
res.end('<h1>home</h1>')
})
// 首页路由
app.get('/', (req, res) => {
res.end('<h1>hello express</h1>')
})
// 创建 post 路由
app.post('/login', (req, res) => {
res.end('<h1>login login</h1>')
})
// 匹配所有的请求方法
app.all('/search', (req, res) => {
res.end('<h1>search search search</h1>')
})
// 自定义 404 路由
app.all('*', (req, res) => {
res.end('<h1>404 Not Found</h1>')
})
// 路由是有先后顺序的,先创建的路由会先执行
// 监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动 端口监听为 3000')
})
3.3 获取请求参数
express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式:
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 获取请求的路由规则
app.get('/request', (req, res) => {
// 1.获取报文的方式与原生 HTTP 获取方式是兼容的(原生请求)
console.log(req.method)
console.log(req.url)
console.log(req.httpVersion)
console.log(req.headers)
console.log('---------------------------')
// 2.express 独有的获取报文的方式
// 获取查询字符串
console.log(req.query) // 『相对重要』
// 获取 url
console.log(req.path)
// 获取指定的请求头
console.log(req.get('host'))
// 获取 ip
console.log(req.ip)
res.end('<h1>hello express</h1>')
})
// 监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动,端口 3000 正在监听中...')
})
3.4 获取路由参数
路由参数指的是 URL 路径中的参数(数据)。语法格式如下:
req.params.占位符
// 注意:占位符是什么,req.params后面跟的就是什么(两者要保持一致)
代码示例:
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 使用占位符(:id),然后根据占位符去获取 URL 路由参数,再根据参数返回不同的页面
app.get('/:id.html', (req, res) => {
// 获取 URL 路由参数
console.log(req.params.id)
let id = req.params.id
res.setHeader('content-type', 'text/html;charset=utf-8')
if(id === 'login') {
res.end('<h1>首页</h1>')
}else if(id === 'money') {
res.end('<h1>商品详情</h1>')
}else {
res.end('<h1>注册页面</h1>')
}
})
// 监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动,端口 3000 正在监听中...')
})
3.5 练习
根据路由参数响应歌手的信息,路径结构如下:
/singer/1.html
显示歌手的姓名和图片,代码示例:
// 导入 express
const express = require('express')
// 导入 json 文件
const {singers} = require('./JSON/singers.json')
// 创建应用对象
const app = express()
// 创建路由
app.get('/singer/:id.html', (req, res) => {
// 获取路由参数
let {id} = req.params
// 在数组中寻找对应 id 的数据
let result = singers.find(item => {
// 判断
if(item.id === Number(id)) {
return true
}
})
// 要判断得到的结果是否为对象,即是否存在该数据
if(!result) {
// 没有的数据,就设置响应状态码为 404
res.statusCode = 404
res.end('<h1>404 Not Found</h1>')
return
}
// 设置响应体,展示最终结果
res.end(`
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>歌手展示</title>
</head>
<body>
<h2>${result.singer_name}</h2>
<img src="${result.singer_pic}" />
</body>
</html>
`)
})
// 监听端口 启动服务
app.listen(9000, () => {
console.log('服务已经启动 端口 9000 正在监听中...')
})
四、express 响应设置
express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式:
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 设置路由
app.get('/response', (req, res) => {
// 1.express 中设置响应的方式兼容 HTTP 模块的方式(原生响应)
// res.statusCode = 404
// res.statusMessage = 'love'
// res.setHeader('xxx', 'yyy')
// res.write('<h1>hello express</h1>')
// res.end('<h1>response</h1>')
// 2.express 独有的设置响应的方法
// res.status(500) //设置响应状态码
// res.set('abc', 'def') //设置响应头
// res.send('你好 Express') //设置响应体(注意:使用 send 方法设置响应体不会出现中文乱码的问题)
// 连贯操作
res.status(404).set('aaa', 'bbb').send('express 框架中可以将这些设置响应连起来')
})
// 监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动 端口 3000 正在监听...')
})
其他响应的设置,代码示例如下:
// 1.导入 express
const express = require('express')
// 2.创建应用对象
const app = express()
// 3.创建路由
app.get('/other', (req, res) => {
// 1.重定向(跳转响应)
res.redirect('https://www.csdn.net/')
// 2.下载响应
res.download(__dirname + '/package.json')
// 3.JSON 响应
res.json({
name: '云墨书生',
slogon: '摆烂太久会被收回天赋!'
})
// 4.文件响应
res.sendFile(__dirname + '/test.html')
})
// 4.监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动,端口 3000 正在监听中...')
})
五、express 中间件
5.1 什么是中间件
中间件(Middleware)本质上是一个回调函数,所以有些时候也可以称之为 中间件函数
中间件函数 可以像路由回调一样访问 请求对象(request)、响应对象(response)
5.2 中间件的作用
中间件的作用 就是 使用函数封装公共操作,简化代码
5.3 中间件的类型
- 全局中间件
- 路由中间件
(1)定义全局中间件
每一个请求 到达服务端之后 都会执行全局中间件函数
定义全局中间件的步骤:
-
声明中间件函数:(函数的形式是没有约束的)
// 声明中间件函数 function 函数名(req, res, next) { // 实现功能代码 ...... // 调用 next 函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用 next) next() } // 或者也可以写成箭头函数 let 函数名 = (req, res, next) => { //实现功能代码 ...... // 调用 next next() }
-
使用中间件函数:
app.use(recordMiddleware)
-
补充:声明中间件函数时可以直接将匿名函数传递给 use(简写方式)
app.use(function (req, res, next) { console.log('我是一个中间件函数') next() })
(2)多个全局中间件
express 允许使用 app.use() 定义多个全局中间件:
app.use(function (req, res, next) {
console.log('这是第一个中间件函数')
next()
})
app.use(function (req, res, next) {
console.log('这是第二个中间件函数')
next()
})
(3)定义路由中间件
如果 只需要对某一些路由进行功能封装,则就需要 路由中间件
调用格式如下:
app.get('/admin', 中间件函数, (req, res) => {
res.send('后台页面')
})
app.get('/setting', 中间件函数1, 中间件函数2, ..., (req, res) => {
res.send('设置页面')
})
代码示例如下:
// 声明中间件函数
let checkCodeMiddleware = (req, res, next) => {
// 判断 URL 中是否 code 参数等于 521
if(req.query.code == '521') {
next()
}else {
res.send('暗号错误')
}
}
let readMiddleware = (req, res, next) => {
console.log('我是一个路由中间件')
next()
}
// 后台
app.get('/admin', checkCodeMiddleware, (req, res) => {
res.send('后台页面')
})
// 后台设置
app.get('/setting', checkCodeMiddleware, readMiddleware, (req, res) => {
res.send('设置页面')
})
5.4 静态资源中间件
express 内置处理静态资源的中间件
// 设置静态资源中间件的格式:
app.use(express.static('静态资源的路径'))
// 例如:将当前文件夹下的 public 目录作为网站的根目录
app.use(express.static(__dirname + '/public'))
代码示例:
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 设置静态资源中间件
app.use(express.static(__dirname + '/public'))
// 如果访问的内容经常变化,还是需要设置路由
// 但是,这里有一个问题:如果 public 目录下有 index.html 文件,同时也有 index.html 的路由(也可以是 / 的路由)
// 此时的情况是:谁书写在前,那么就优先执行谁
// index.html 文件是默认打开的资源
app.get('/index.html', (req, res) => {
res.send('我才是首页~~~')
})
// 监听端口 启动服务
app.listen(9000, () => {
console.log('服务已经启动 端口 9000 监听中...')
})
注意事项:
- index.html 文件为默认打开的资源
- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 路由响应动态资源,静态资源中间件响应静态资源(一般情况下)
练习
需求:局域网内可以访问尚品汇的网页
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 设置静态资源中间件
app.use(express.static(__dirname + '/尚品汇'))
// 监听端口 启动服务
app.listen(9000, () => {
console.log('服务已经启动 端口 9000 监听中...')
})
5.5 获取请求体数据 body-parser
express 可以使用 body-parser
包处理请求体
-
安装:
npm i body-parser
-
导入 body-parser 包
const bodyParser = require('body-parser')
-
获取中间件函数
// 解析 JSON 格式的请求体的中间件 var jsonParser = bodyParser.json() // 解析 querystring 格式请求体的中间件 var urlencodedParser = bodyParser.urlencoded({ extended: false })
-
设置路由中间件,然后使用
req.body
来获取请求体数据app.post('/login', urlencodedParser, (req, res) => { // 获取请求体数据 console.log(req.body) // 获取用户名 console.log(req.body.username) // 获取密码 console.log(req.body.password) res.send('获取表单中的数据') })
-
获取到的请求体数据:
[Object: null prototype] { username: 'admin', password: '123456' }
5.6 图片防盗链
图片防盗链原理:http 标准协议中有专门的字段记录 referer
- 它可以追溯到请求时从哪个网站链接过来的
- 对于资源文件,可以跟踪到包含显示它的网页地址是什么
因此所有的防盗链方法都是基于这个 Referer 字段
// 导入 express
const express = require('express')
// 创建应用对象
const app = express()
// 声明中间件
app.use((req, res, next) => {
// 检查请求头中的 referer 是否为 127.0.0.1
// 获取 referer
let referer = req.get('referer')
if(referer) {
// 实例化
let url = new URL(referer)
// 获取 hostname
let hostname = url.hostname
// 判断
if(hostname !== '127.0.0.1') {
// 响应 404
res.status(404).send('<h1>404 Not Found</h1>')
return
}
}
next()
})
// 设置静态资源中间件
app.use(express.static(__dirname + '/public'))
// 监听端口 启动服务
app.listen(9000, () => {
console.log('服务已经启动 端口 9000 监听中...')
})
六、Router
6.1 什么是 Router
express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象
6.2 Router 作用
对路由进行模块化,更好的管理路由
6.3 Router 使用
-
创建独立的 JS 文件(homeRouter.js):
// 1.导入 express const express = require('express') // 2.创建路由对象(相当于一个小型的 app 对象) const router = express.Router() // 3.创建路由规则 router.get('/home', (req, res) => { res.send('前台首页') }) router.get('/search', (req, res) => { res.send('内容搜索') }) // 4.对外暴露 router module.exports = router
-
在主文件中导入子路由文件并使用:
// 导入 express const express = require('express') // 导入 router const homeRouter = require('./routes/homeRouter') const adminRouter = require('./routes/adminRouter') // 创建服务对象 const app = express() // 设置 app.use(homeRouter) app.use(adminRouter) app.all('*', (req, res) => { res.status(404) res.send('<h1>404 Not Found</h1>') }) // 监听端口 启动服务 app.listen(3000, () => { console.log('服务已经启动 端口 3000 监听中...') })
七、EJS 模板引擎
7.1 什么是模板引擎
模板引擎是分离 用户界面和业务逻辑 的一种技术
7.2 什么是 EJS
EJS 是一个高效的 JavaScript 的模板引擎:
7.3 EJS 初体验
-
下载安装 EJS
npm i ejs
-
代码实例:
// 1.引入ejs const ejs = require('ejs') // 2.定义数据 let person = ['张三','李四','王二麻子'] // 3.ejs解析模板返回结构 // <%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构 let html = ejs.render(‘<%= person.join(",") %>’, {person:person}) // 4.输出结果 console.log(html)
7.4 EJS 常用语法
-
执行 JS 代码
<% code %>
代码实例:
/** * 需求: * 将数组中的元素按照<ul><li>xxx</li>...</ul>的形式输出 */ // 导入 ejs const ejs = require('ejs') const fs = require('fs') const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'] // EJS 实现 // <% %> 可以用来执行 JS 代码 let result = ejs.render(`<ul> <% xiyou.forEach(item => { %> <li><%= item %></li> <% }) %> </ul>`, {xiyou}) console.log(result)
-
输出转义的数据到模板上
<%= code %>
-
输出非转义的数据到模板上
<%- code %>
7.5 express 中使用 ejs
-
设置模板引擎
app.set('view engine', 'ejs')
-
设置模板文件存放位置(模板文件:具有模板语法内容的文件)
app.set('模板文件夹名称', '模板文件夹路径') // 例如: app.set('views', path.resolve(__dirname, './views'))
-
通过 render 方法响应
// 格式: res.render('模板文件名', '数据') app.get('/', (req, res) => { let title = '云陌殇 君子剑' res.render('home', {title}) })
-
创建模板文件(后缀名为:ejs)
代码示例如下:
// 导入 express
const express = require('express')
// 导入 path
const path = require('path')
// 创建应用对象
const app = express()
// 1.设置模板引擎(ejs 只是 node.js 模板引擎中的一个。比如:pug、twing)
app.set('view engine', 'ejs')
// 2.设置模板文件存放位置 模板文件:具有模板语法内容的文件
app.set('views', path.resolve(__dirname, './views'))
// 创建路由
app.get('/', (req, res) => {
// 3.通过 render 方法响应
// 格式:res.render('模板的文件名', '数据')
// 声明变量
let title = '云陌殇 君子剑'
res.render('home', {title})
// 4.创建模板文件(例如:home.ejs)
})
// 监听端口
app.listen(9000, () => {
console.log('服务已经启动...')
})
八、express-generator 工具
通过应用生成器工具 express-generator
可以快速创建一个应用的骨架。下载方式:
-
通过 npx(包含在 Node.js 8.2.0 及更高版本中)命令来运行 Express 应用程序生成器:(后面会学到 npx)
npx express-generator
-
通过 npm 将 Express 应用程序生成器安装到全局环境中并使用:
npm install -g express-generator
通过 express -h
可以列出所有可用的命令行参数:
express -h
Usage: express [options] [dir]
Options:
-h, --help 输出使用方法
--version 输出版本号
-e, --ejs 添加对 ejs 模板引擎的支持
--hbs 添加对 handlebars 模板引擎的支持
--pug 添加对 pug 模板引擎的支持
-H, --hogan 添加对 hogan.js 模板引擎的支持
--no-view 创建不带视图引擎的项目
-v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎)
-c, --css <engine> 添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件)
--git 添加 .gitignore
-f, --force 强制在非空目录下创建
创建一个 Express 应用的语法:
express -e 文件夹的名称
// 例如:
express -e generator
入口文件是 bin 目录下的 www.js 文件