Express框架学习
Express
路由
-
请求方法和路由路径一起定义了请求的端点。
-
路由路径可以是
字符串、字符串模式或正则表达式。
-
使用
字符串
的路由路径示例: -
使用
字符串模式
的路由路径示例::
占位符,占位符后的名称任意、常见详情页面接口、常用?
前一个字符重复0次或1次+
号 前一个字符重复1次或多次*
号 任意一个字符,与正则表达式里面的*
不一样,与正则表达式中的.
是一个意思 -
使用
正则表达式
的路由路径示例:
-
-
中间件
路由规则可以处理多个回调函数,将这些回调函数称为中间件。
为什么需要中间件?
- 防止单个路由规则下的函数过长
- 多个路由规则可能有重复的操作,封装到一个中间件中,防止重复
- 加强内聚、减少耦合
路由规则使用多个回调函数的关键点
-
写在前面的回调函数需要添加一个重要的参数
next
-
注意
-
如果当前中间件函数没有结束请求/响应循环,那么它必须调用
next()
,以将控制权传递给下一个中间件函数。 -
res.send()
结束执行,该方法封装了write和end,而且无需写请求头res.send()
后面写next()
,后面的代码也不会执行;res.send()
类似于函数的return
,后面的代码不会再执行。 -
next()
放行,继续向后面的回调函数执行
-
-
如果执行完该回调函数继续向下执行其他的回调函数,执行
next()
方法// 假设定义了两个函数表达式fun1、fun2; // 这样两种调用方式都可以 app.get("/home",fun1,fun2) app.get("/home",[fun1,fun2]) // 或者数组和函数的混合写法 app.get("/home",[fun1,fun2],(req,rpo){ // 代码块 })
-
如何让各个中间件之间通信?比如,将前一个中间件返回的结果给下一个中间件使用。
-
多个中间件之间,共享同一份req和res。
-
基于这样的特性,可以在上游的中间件中,统一为req或 res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
-
中间件
路由中间件不是把app.get(‘’)整体写出去,这样还需要调用app方法,耦合度太高。
是把app对象中的回调函数拆分出去,写在模块里。
中间件是一个函数,他可以访问请求对象、响应对象和处于请求-响应循环流程的中间件(next变量)。
Express应用可以使用如下几种中间件:
- 应用级中间件 挂在app对象上
- 路由级中间件 挂在router对象上
- 错误处理中间件 写在所有路由规则最后面
- 内置中间件
- 第三方中间件
挂在不同对象身上,区分各个中间件。
应用级中间件
-
应用级别的中间件挂在app对象上
-
使用场景:
-
如果所有的路由规则都需要执行回调函数,写在app.method(请求路径,回调函数),那么要写很多次,造成很多重复工作。
-
解决方法:使用应用级中间件,
对所有的请求都执行某个操作
。
-
-
应用级中间件绑定到
app对象
上,使用方法:-
app.use() ** 常用**
-
app.method()
上述方法中不需要写请求路径,就是万能匹配。(也可以写,但是一般不写)
其中,method是http请求的方法、如get、post等,全部需要小写
// 中间件需要添加next参数! app.use((request,response,next)=>{ console.log('身份验证成功!') next() })
-
-
注意
-
注意应用级中间件代码书写的位置。
假设有验证tooken的中间件,现在登录、注册的页面则不需要验证token,所以该验证token的应用级中间件app.use()需要写在
登录、注册页面
路由规则的后面。 -
只要匹配的是app其实都是应用级别的中间件。
只不过写不写路径,会让应用级别中间件变为:万能匹配中间件、特定路径的中间件
-
路由级别中间件
-
路由中间件挂在Router()对象上
一般都是单独写一个模块,里面存放路由级别中间件,然后暴露数据;
-
请求路径的拼接方法:
路径1:主文件app.use()/app.method()方法里路径
路径2:路由模块里面的router.method()里写的路:
路径1和路径2拼接共同构成了真正的 路由规则的请求路径。
-
路径2不写,那么就是路径1+/下面的所有子目录
- 路径2是
/
,那么就是路径1/login/ = /login
- 路径2写具体路径,那么就是路径1+路径2
-
-
应用场景:
以后再写路由规则的时候,如果觉得他们是一类的,那么就可以放心大胆的提出到模块中单独写,然后在接口处成为应用级别的中间件。
错误处理中间件
- 一定要写在所有路由规则最后面 ,写在主要页面的的所有应用级中间件的最后面
// 第一种写法
app.use((req,res)=>{
res.status(404).send('找不到页面')
})
// 第二种写法,使用4个参数,而不是3个
app.use(function(err,req,res,next){
console.err(err.stack)
res.tatus(404).send('找不到页面')
})
内置中间件
-
express.static
是Epress唯一内置的中间件。 -
它基于serve-static,负责在Express应用中托管静态资源。每个应用可有多个静态目录。
-
静态资源目录和网站文件目录是一个东西。
app.use(express.static('./public')) app.use(express.static('./uploads')) app.use(express.static('./files'))
注意点:
-
设置了静态资源中间件后,用户访问网站(不添加请求路径)会自动返回
index.html
文件。 -
所以就会有个问题:
-
情景:假设用户发出
协议、域名、端口/index.html
的请求, -
问题:后台服务既定义了静态资源中间件、又单独设置了
index.html
的路由,那么应该执行哪个路由规则? -
方法:谁书写在前面,就优先执行谁
-
注意事项:
index.html 文件为默认打开的资源
如果静态资源与路由规则同时匹配,谁先匹配谁就响应
路由响应动态资源,静态资源中间件响应静态资源
第三方中间件
安装所需功能的node模块,并在应用中加载;可以在应用级加载,也可以在路由级加载。
举例:安装并加载解析cookie的中间件:cookie-parser
npm install cookie-parser
const express = require('express')
const app = express()
const cookieParser = require('cookie-parser')
// 加载用于解析cookie的中间件
app.use(cookieParser())
获得请求参数
获得get请求参数
-
获得查询字符串
// http原生方法,返回字符串;字符串的内容是?及之后的数据 req.url // express方法获得查询字符串,返回对象 req.query
获得post请求参数
-
获得查询字符串
-
前端传给后端的请求字符串放在了请求体中,所以直接获得请求体中的数据即可。
-
post请求字符串的格式有两种
-
form格式
:name=value&…&name=value -
json字符串格式
:{‘key1’:value,’key2’:value}value是否加双引号由value的数据类型决定,字符串需要加,数字类型不需要加。
-
// 路由规则中,返回对象 req.body
在接口中,路由响应前添加以下代码:后端既可以获得前端form格式的请求字符串、也可以获得json格式的请求字符串
// 使用req.body方法,必须在主文件配置解析post参数的中间件:express的内置方法 // 不需要下载第三方模块body-parse(网上90%教程都要下载第三方中间件) app.use(express.urlencoded({extended:false})) // 解析form格式 // 解析前端的json格式字符串的中间件 app.use(express.json()) // 解析json格式
-
设置响应参数
-
响应行
// 响应状态码 res.status() // 响应描述 res.statusMessage() // 这是http原生方法
-
响应头
res.set('xxx','yyy')
-
响应体
// express方法 res.send() // http原生方法 res.wirte() res.end()
利用Express托管静态文件
-
配置静态资源目录的作用
配置静态资源目录后,当用户输入URL访问某个路径后:
express会自动去静态资源目录下查找并返回相关的内容(如果有);而无需再手写各种路由规则。
**简单来说就是根据完整路径直接找到页面。** -
配置方法
-
利用Express内置的
express.static
可以方便的托管静态文件,例如图片、CSS、JavaScript文件等。 -
将静态资源文件所在的目录作为参数传递给express.static中间件
就可以提供静态资源文件的访问
。
app.use(express.static('./public')) // 当前目录下的public文件夹作为静态资源目录
-
在浏览器地址栏输入url时,url中不会出现静态资源目录。
根据URL后的查询路径,直接在静态资源目录下查找对应的路径和文件。
- 配置多个静态资源文件。
app.use(express.static('./public'))
app.use(express.static('./static'))
访问静态资源文件时,express.static中间件会根据目录添加的顺序查找所需的文件。
如果不同目录下都有用户查询的文件,会返回第一个查找到的文件。
路由规则主要是动态资源的应对方式
SSR服务器渲染(模板引擎)
渲染数据的方式有两种
-
服务器渲染(server side rendering,ssr) ,后端渲染模板。
-
前端做好静态页面和交互效果
-
前端代码提供给后端,后端要把静态html及其里面的假数据删掉
-
通过模板 动态生成html内容
可以使用ejs模板实现后端渲染
使用ejs实现,用户输入对应的路径(不写.html)系统直接返回对应的Html文件
(也不用写路由规则)
-
-
前后端分离,BSR,前端中组装页面
- json模拟/ajax交换数据
- 前后端通过一种通用的数据形式:json数据 通信。
-
本节介绍服务器渲染的一种方式:ejs模板。
- 首先需要安装ejs第三方工具。
npm i ejs
-
在应用中进行如下设置才能让Express渲染模板文件:
-
创建views文件夹,存放
.ejs
结尾的文件(也可以是.html
结尾的文件)ejs语法
<% %> // 流程控制标签 <%= %> // 输出内容,html标签不会被解析 <%- %> // 输出内容,html标签会被解析 <%# %> // 注释标签,且在浏览器不现实注释 <%- include %> //导入公共的模板内容
-
在代码中进行设置
渲染ejs文件,传送给前端
// 如果views文件夹存放的是.ejs结尾的文件,就需要在入口文件中设置以下代码 app.set('views','./views') app.set('view engine','ejs') // 模板引擎
不想渲染ejs文件,想直接渲染html文件
// 如果views文件夹存放的是.html结尾的文件,就需要在入口文件中设置以下代码 app.set('views','./views') app.set('view engine','html') // 模板引擎 app.engine('html',require('ejs').renderFile) // 支持直接渲染html文件
-
-
使用模板引擎的好处?
-
实现html和入口处后端数据的分离
单独书写
ejs
,然后在入口模块将数据传进去 -
可以让用户通过不带后缀的
.html
的路径,但还是可以获得对应的.html
资源
-
-
问题:在上一节,设置了静态资源目录,用户可以根据完整的路径.html的方式获得对应资源。(无需写路由规则)。但是在大部分情况下,用户都是在浏览器输入了一个.html后缀的路径,就可以获得.html后缀的对应资源,怎么实现?
-
解决方法:使用模板引擎
app.set
,就可以直接根据路径直接返回.html
的文件。
res.josn() 传输json数据
res.send() 传输josn和html
res.render() 传输模板数据
express生成器
-
作用:应用生成器工具
express-generator
可以快速生成项目的骨架,而不用手动创建各个文件夹。 -
需要创建的文件夹有
-
静态资源目录
public/static
-
路由模块
router
-
使用npm自动创建的目录
node_modules
以及package.json、package-lock.json
- views目录 放ejs模板
- index.js文件
-
-
创建方法:
# 第一步,安装
npm i express-generaor
npm i -g express-generaor # 全局安装
# 第二步,创建项目骨架
express # 在当前工作目录中创建项目骨架
express <filename> # 指定创建的项目名称