Express
Express是一个基于Node.js平台的,快速、开放、极简的Web开发框架
可以用于开发Web服务器
和API接口服务器
。
是对Nodejs内置API的封装,类似WebAPIs
和Jquery
的关系。
使用Express
1 | npm i express -S |
1 | const express = require('express') |
创建Web服务器
1 | const express = require('express'); |
监听GET请求
1 | app.get('/访问地址',(req,res)=>{ |
监听POST请求
1 | app.post('/访问地址',(req,res)=>{ |
相应内容到客户端
end()
方法可以返回普通字符串
对象也可以返回json
对象
1 | res.end(); |
获取url中的查询参数
1 | app.get('/user/?id=1',(req,res)=>{ |
获取url中的动态参数
使用:
匹配动态参数(路径参数),举例如下:
1 | app.get('/user/:id',(req,res)=>{ |
创建静态资源服务器
使用use()
方法挂载路径前缀
1 | app.use(express.static('文件夹路径')) |
Express路由
在Express中,路由指客户端的请求
和服务器处理函数
之间的映射关系。
1 | app.METHOD('/...',function(req,res){ |
匹配过程
模块化路由
不建议直接将路由挂载app
上,推荐将路由抽离为单个模块。
- 创建路由模块对应的js文件。
- 调用
express.Router()
函数创建路由对象。
1 | const express=require('express'); |
- 向路由对象上挂载具体的路由。
1 | router.METHOD('/...',function(req,res){ |
- 使用
module.exports
向外共享路由对象。
1 | module.exports=router |
- 使用
app.use()
函数注册路由模块。
中间件
在接收到请求后,往往不会只进行依次处理,而要经过多个中间件。
中间件函数与路由函数
中间件函数相对于路由函数多了一个next
参数和next()
函数的调用。
1 | app.get('/...',function(res.req,next){ |
next()函数
是实现多个中间件连续调用的关键,它将处理结果转交给下一个中间件或路由。
全局生效中间件
1 | app.use(中间件函数1) |
中间件会根据代码顺序对结果进行传递。
中间件的作用
中间件函数可以对所有的请求进行一些预处理。比如:挂载一些新的参数,req.新参数=参数值
;将每个路由中相同的操作抽离作为中间件,这样就不需要每个路由都写一遍了。
局部生效的中间件
这里的局部生效是指在某个特定的路由中生效的中间件。
1 | app.get('/...',中间件函数1,中间件函数2,...,路由函数) //写多个参数的形式添加中间件 |
中间件分类
- 应用级别的中间件
将中间件绑定到app
上,如:app.get()、app.use()等。
- 路由级别的中间件
将中间件绑定到router
上,如:router.get()、router.use()等。
- 错误级别的中间件
错误级别的中间件专门用来捕获整个项目中发生的异常错误,从而防止项目崩溃的问题。
错误级别的中间件函数多了一个err
参数。注意顺序。
1 | const mw=function(err,req,res,next){ |
Express内置的中间件
- express.static快速托管静态资源。
- express.json解析JSON格式的请求数据。(express版本要求 4.16+)
- express.urlencoded解析URL-encoded格式的请求数据。(express版本要求 4.16+)
Express解析urlencoded格式的数据
默认情况下,如果不配置解析表单的中间件,req.body
值为undefined
。
可以通过contentType
设置发送的数据类型。
1 | app.use(express.urlencoded({ extended: false })) //用于获取urlencoded格式的数据 |
Express解析JSON格式的数据
1 | // app.use(express.urlencoded({ extended: false })) //用于获取urlencoded格式的数据 |
req的事件
data事件
在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据。如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
1 | app.use((req,res)=>{ |
end事件
当请求体数据接收完毕之后,会自动触发 req 的 end 事件。
因此,我们可以在 req 的 end 事件中,拿到并处理完整的请求体数据。
1 | // 导入处理querystring的Node.js内置模块 |
中间件模块化
类似路由模块化。
网络资源请求
由于请求协议
、端口
等因素的影响导致出现跨域错误。一般使用CORS
方案进行解决。
cors是Express的一个第三方中间件。
1 | npm i cors |
1 | const cors = require('cors'); |
解决跨域资源共享
1. 设置响应头部
Access-Control-Allow-Origin
可以设置哪些服务器
可以访问资源。可以使用*
代表所有域名。
1 | res.setHeader('Access-Control-Allow-Origin','https://lptexas.top/') |
Access-Control-Allow-Header
可以设置需要发送的额外头信息。
默认情况CORS仅支持客户端向服务器
发送下方9个请求头:
1 | res.setHeader('Access-Control-Allow-Header','可以使用逗号分割多个') |
Access-Control-Allow-Methods
设置额外允许的请求方式。
默认情况CORS仅支持get、post、head请求。可以使用*
代表所有请求。
1 | res.setHeader('Access-Control-Allow-Methods','可以使用逗号分隔多个') |
2. 使用cors模块
1 | cors({ |
3. JSONP
浏览器端通过<script>标签的src属性,请求服务器上的数据,同时服务器返回一个函数调用。这种请求数据的方式叫做JSONP。
特点
JSONP不属于真正的Ajax请求,因为没有使用XMLHttpRequset对象。
JSONP仅支持GET请求。
简单请求和预检请求
简单请求:客户端和服务器端只会发生一次请求。
预检请求:客户端与服务器之间发生两次请求,OPTION预检请求成功之后,才会发送真正的请求。
nodemon工具
实现热部署。
监听代码变化,重新执行代码。
1 | npm i nodemon -g |
使用方法
使用nodemon
命令替代node
1 | nodemon app.js |
Mysql
安装mysql
1 | npm i mysql |
配置和连接数据库
1 | const mysql = require('mysql'); |
测试数据库连接
1 | db.query('sql语句',function(error,results){ |
使用占位符
在sql语句中,可以使用?
作为占位符。在使用数组一次指定占位符中的具体值。
1 | db.query('sql语句',[占位符值1,占位符值2,...],callback) |
快速的插入多个属性
1 | const data={字段1:"值1",字段2:"值2"}; |
更新操作
1 | const sql='update 表名 set 属性=值,属性=值 where 属性=值' |
删除操作
1 | const sql='delete from 表名 where 属性=值' |
身份认证
如扫码登录、手机验证码登录等。
Session认证机制
建议服务端渲染方式使用。
HTTP协议的无状态性
服务器不会主动保留每次HTTP请求的状态。每次请求都是独立的。
打破无状态性
服务器为某次请求发放身份标识Cookie
。
用户第一次请求服务器时,服务器通过响应头
,向客户端发送一个身份Cookie,客户端会自动将Cookie保存在浏览器中。
随后,每次客户端访问浏览器,浏览器会自动将身份认证相关的Cookie,通过请求头的形式,发送给服务器,服务器会鉴别客户端身份。
Cookie很容易伪造,不具有安全性。
提高身份认证安全性
客户端Cookie+服务器Cookie认证
Session认证机制的精髓。
Session工作原理
在Express中使用Session认证
1 | npm i express-session |
1 | const express=require('express'); |
向session中存数据
配置完毕后,可以使用req.session
,来访问和使用session对象。
1 | app.post('/...',(req,res)=>{ |
取session中的数据
1 | app.get('/...',(req,res)=>{ |
清空session
1 | req.session.destroy(); |
JWT认证机制
推荐前后端分离方式使用。
Session认证机制需要配合Cookie才能实现。由于Cookie默认不支持跨域访问,所以当涉及前端跨域请求后端接口时,需要做很多额外配置,才能实现跨域Session认证。
当前端需要跨域请求后端接口时,推荐使用JWT认证机制
。
JWT是什么?
JWT,JSON Web token是目前最流行的跨域认证解决方案。
工作原理
用户信息通过Token字符串的形式,保存在客户端浏览器中。服务器通过还原Token字符串的形式来认证用户的身份。
JWT组成部分
Header头部、Payload有效负载、Signature签名。
xxxxxxxxxx25 1// 引入 events 模块2var events = require(‘events’);3// 创建 eventEmitter 对象4var eventEmitter = new events.EventEmitter();5 6// 创建事件处理程序7var connectHandler = function connected() {8 console.log(‘连接成功。’);9 10 // 触发 data_received 事件 11 eventEmitter.emit(‘data_received’);12}13 14// 绑定 connection 事件处理程序15eventEmitter.on(‘connection’, connectHandler);16 17// 使用匿名函数绑定 data_received 事件18eventEmitter.on(‘data_received’, function(){19 console.log(‘数据接收成功。’);20});21 22// 触发 connection 事件 23eventEmitter.emit(‘connection’);24 25console.log(“程序执行完毕。”);shell
1 | Header.Payload.Signature |
- Header头部和Signature签名,属于安全性相关部分,用于保证Token的安全性。
- Payload有效负载,真正的信息,它由用户信息加密后生成。
JWT使用方式
客户端收到的JWT保存在localStorage
或sessionStorage
中。
客户端与服务器通信一般将JWT字符
放在头部
的Authorization
字段中。
1 | npm i jsonwebtoken express-jwt |
1 | const jwt = require('jsonwebtoken'); |
登录成功后生成jwt字符串,响应给客户端
调用jsonwebtoken
中的sign()
方法。
1 | jsonwebtoken.sign(用户的信息对象,加密的密钥,配置对象如可以配置当前token的时间) |
1 | const secretKey='LPtexas' |
将jwt字符串还原为json对象
使用express-jwt
中间件,调用unless({{path:["/..."]}})
方法可以指定哪些接口不需要访问权限。
1 | //5.3.3之前的版本使用: |
将jwt字符串放入头部
的Authorization
的字段中
注意需要再值前添加Bearer
使用req.user
获取用户信息
使用了express-jwt后,jwt解析的结果被挂载到了req.user属性中。
1 | //5.3.3版本以前使用: |
捕获解析jwt失败后产生的错误
使用一个中间件来解决。
1 | app.use((err, req, res, next) => { |
定义secret密钥
用于保证JWT字符串的安全性。
用于加密和解密JWT。
越复杂越好。
1 | const secretKey = '我是一个复杂的字符串' |