express中间件
express的中间件本质上就是一个function处理函数
const express = require('express') const app = express(); app.get('/',function(req,res.next){ next() })
注:中间件函数的形参列表中,必须包含next参数,而路由处理函数中只包含req,res参数
next()函数是实现多个中间件连续调用的关键,他表示把流转关系转交给下一个中间件或路由
全局 生效的中间件:
使用app.use()定义的中间件
局部生效的中间件:
不使用app.use()定义的中间件
定义多个局部中间件:
//以下两种写法是"“完全等价"的,可根据自己的喜好,选择任意一种方式进行使用 app.get( ‘/’ ,mw1,mw2,(req, res) => { res.send( " Home page.”) app.get( ‘/’,[mw1,mw2],(req,res) => { res.send( ’ Home page."))
中间件的注意事项:
1.一定要在路由之前注册中间件
2.客户端发送过来的请求,可以连续调用多个中间件进行处理
3.执行完中间件的业务代码之后,不要忘记调用next)函数
4.为了防止代码逻辑混乱,调用next(函数后不要再写额外的代码连续调5.用多个中间件时,多个中间件之间,共享req和res对象
中间件的分类:
- 路由级别的中间件:
绑定到express.Router()实例上的中间件,叫做路由级别的中间件
var app = express() var router = app.Router() router.use(function(req,res,next){ console.log('Time',Date.new()) next() }) app.use('/',router)
- 应用级别的中间件:
通过app.use()或者app.get()或app.post(),绑定到app实例上的中间件,叫做应用级别的中间件
//应用级别的中间件(全局中间件) app.use((req,res,next)=>{ next() }) //应用级别的中间件(局部中间件) app.get('/',nm,(req,res)=>{ res.send('home page') })
- 错误级别的中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
**格式:**错误级别中间件的 function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)。 app.get( ' /", function (req,res) { //路由 throw new Error("服务器内部发生了错误!')//抛出一个自定义的误 res.send( "Home Page") }) app.use(function (err, req,res,next){//错汉极励的中问件 console.log( "发生了错误: ' +err.message) // 在服务器打印消息 res.send('Error! ' + err.message)//向客户靠家应错误相关的内容 })
注:要把错误级别的中间件放在全部路由之后
express内置的中间件
express.static 快速托管静态资源的内置中间件,例如:HTML
文件、图片、CSS样式等(无兼容性)
express.json解析JSON格式的请求体数据(有兼容性,仅在
4.16.0+版本中可用)
express.urlencoded 解析URL-encoded格式的请求体数据(有
兼容性,仅在4.16.0版本中可用)
//配置解析application/json格式敖据的内置中问件 app.use( express.json(o) //配置解析application/x-www-form-urlencoded格式数据的内置中间件 app.use(express.urlencoded({ extended: false }
第三方的中间件
非 Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
以使用body-parser这个第三方中间件为演示步骤:
运行npm install body-parser安装中间件
使用require 导入中间件
调用app.use()注册并使用中间件
自定义中间件
实现步骤:
- 定义中间件
- 监听req的data事件
- 监听req的end事件
- 使用querystring模块解析请求体数据
- 将解析出来的数据对象挂载为req.body
- 将自定义中间件封装为模块
1.定义中间件
app.use(function(req.res,next) { //中间件的业务逻辑 })
2.监听req的data事件
//定义变量。用来存储名户读发送过来的请求体数据 let str = " " //监听req对象的 data 事件(客户读发试过来的新的清求体数购) req.on( ‘data' , (chunk)=>i //拼接请求体数据,转换为宁符串 str += chunk
3.监听req的end事件
//监听req对象的end 事件(请求体发送完毕后自动触发) req.on( " end",()=>{ //打印完整的请求体数据 console.log(str) //TOD0:把字符串格式的请求体数据,解析成对象格式 }
4.使用querystring模块解析请求体数据
//导入处理querystring的 Node.js内置模块 const qs = require( " querystring " ) //调用qs.parse()方法,把查询字符串解析为对象 const body = qs.parse(str)
5.将解析出来的数据对象挂载为req.body
req.on( " end' , ()> { const body = qs.parse(str) // 调用qs.parse()方法,把查询字符串解断为对象 req.body = body //将解析出来的清求体对象。挂载为req.body属性 next() //最后,一定要调用next()函数,执行后续的业务逻辑 })
6.将自定义中间件封装为模块
编写接口
使用express编写接口
1.创建一个服务器
const express = require('express') const app = express() app.listen(80,()=>{ conlose.log('http://127.0.0.1') })
2.创建API路由模块
// apiRouter.js【路由模块】 const express - require( " express ') const apiRouter = express.Routero // bind your router here.. . module.exports = apiRouter // app.js 【导入并注册路由模块】 const apiRouter = require( " ./apiRouter.js ") app.use( ' /api ' , apiRouter)
解决跨域问题:
解决接口跨域问题的方案主要有两种:
CORS(主流的解决方案,推荐使用)
JSONP(有缺陷的解决方案:只支持GET请求)
使用cors中间件解决跨域问题:
cors 是Express的一个第三方中间件。通过安装和配置cors中间件,可以很方便地解决跨域问题。使用步骤分为如下3步: 1.运行npm install cors安装中间件 2.使用const cors = require("cors')导入中间件 3在路由之前调用app.use(cors0)配置中间件
CORS跨域资源共享
- CORS响应头部-Access-Control-Allow-Origin
响应头部中可以携带一个Access-Control-Allow-Origin字段,其语法如下:
Access-Control-Allow-Origin: l*
其中,origin参数的值指定了允许访问该资源的外域URL。 例如,下面的字段值将只允许来自http://itcast.cn 的请求:
res.setHeader( ’ Access-Control-Allow-Origin" , "http:llitcast.cn’) 如果指定了Access-Control-Allow-Origin字段的值为通配符*,表示允许来自任何域的请求,示例代码如下: res.setHeader( ' Access-Control-Allow-Origin" , "*")
- Access-Control-Allow-Headers
默认情况下,CORS仅支持客户端向服务器发送如下的9个请求头: Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width ,Content-Type(值仅限于text/plain、multipart/form-data、application/x-www-form-urlencoded三者之一) 如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control-Allow-Headers 对额外的请求头进行声明。否则这次请求会失败! //允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头 //注意;多个请求头之间使用英文的运号进行分割 3 res.setHeader( ’ Access-Control-Allow-Headers’,‘Content-Type’,'X-Custom-Header ')
- Access-Control-Allow-Methods
默认情况下,CORS仅支持客户端发起GET、POST、HEAD请求。 如果客户端希望通过PUT、DELETE等方式请求服务器的资源,则需要在服务器端,通过Access-Control-Alow-Methods来指明实际请求所允许使用的 HITP方法。 示例代码如下: //只允许POST、GET、DELETE、HEAD请求方法 res.setHeader( " Access-Control-Allow-Methods’,"POST,GET,DELETE,HEAD’) //允许所有的HTTP请求方法 res.setHeader( " Access-control-Allow-Methods " , "*')
cors请求
- 简单请求
同时满足以下两大条件的请求,就属于简单请求:
请求方式:GET、POST、HEAD三者之一
HTTP头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR.Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-form-
urlencoded、multipart/form-data、text/plain)
- 预检请求
只要符合以下任何一个条件的请求,都需要进行预检请求:
请求方式为GET、POST、HEAD之外的请求
Method类型请求头中包含自定义头部字段
向服务器发送了application/json格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据.
简单请求和预检请求的区别:
简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求
JSONP接口
概念:浏览器端通过
特点:1.JSONP不属于真正的Ajax请求,因为它没有使用XMLHttpRequest这个对象。
2.JSONP仅支持GET请求。不支持POST、PUT、DELETE 等请求。
创建JSONP接口的注意事项:
如果项目中已经配置了CORS跨域资源共享,为了防止冲突,必须在配置CORS中间件之前声明JSONP的接口。否则JSONP接口会被处理成开启了CORS的接口。示例代码如下:
//优先创建JsONP接口【[这个接口不会被处理成CORS接口】 app.get( " /api/jsonp ' . (req, res) =>{}) //再配置CORS中问件【后续的所有接口,都会帔处理成CORS 接口】 app.use(cors()) //这是一个开启了CORS 的接口 sapp.get( " /api/get". (req. res) =>{ })
实现JSONP接口额步骤:
1.获取客户端发送过来的回调函数的名字
const functionName = req.query.callback
2.得到要通过JSONP形式发送给客户端的数据
3.根据前两步得到的数据,拼接出一个函数调用的字符串
4.把上一步拼接得到的字符串,响应给客户端的