文章目录
- 1. 参数
- 1.1 获取URL中的动态参数
- 2. 静态资源
- 2.1 挂载路径前缀
- 3. nodemon
- 4.1路由
- 4.1 路由的匹配过程
- 4.2 模块化路由
- 4.3 为路由模块添加前缀
- 5. 中间件
- 5.1 全局生效的中间件
- 5.2 全局生效中间件的简化形式
- 5.3 中间件的作用
- 5.4 局部生效的中间件
- 5.5 定义多个局部中间件
- 5.6 使用中间件的五个注意事项
- 5.7 中间件分类
- 5.7.1 应用级别的中间件
- 5.7.2 路由级别的中间件
- 5.7.3 错误级别的中间件
- 5.7.4 Express 内置的中间件
- 5.7.5 第三方的中间件
- 5.7.6 自定义中间件
- 6. 跨域资源共享
- 6.1 使用CORS跨域资源共享
- 6.2 CORS的注意事项
- 6.3 CORS响应头
- 6.3.1 Access-Control-Allow-Origin
- 6.3.2 Access-Control-Allow-Headers
- 6.3.3 Access-Control-Allow-Methods
- 6.4 CORS请求的分类
- 6.4.1 简单请求
- 6.4.2 预检请求
- 7. JSONP接口
- 7.1.1 使用JSONP接口的步骤
- Express 的作用 和 Node.js内置的http模块 类似,我们可以方便、快速的创建Web网站服务器(专门对外提供Web网页资源的服务器)或API接口服务器(专门对外提供API接口的服务器)
- Express的本质:就是一个npm上的第三方包,其基于内置的http模块进一步封装,能够极大的提高开发效率
1. 参数
1.1 获取URL中的动态参数
通过req.params对象,可以访问到URL中,通过 : 匹配到的动态参数
app.post('/user/:id/:name', (req, res) => {
const q = req.params;
console.log(q);
res.send(q);
})
POST :http://127.0.0.1:8081/user/1001/zhangsan
2. 静态资源
express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以创建一个静态资源服务器。
如果要托管多个静态资源目录,需要多次调用 express.static() 函数
2.1 挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式
//express.static(),通过它,我们可以创建一个静态资源服务器
// http://127.0.0.1:8080/loess/body.html
app.use( '/loess',express.static('../../file'));
3. nodemon
nodemon 它能够监听项目文件的变动,当代码被修改后,nodemon 会自动帮我们重启项目,代替了手动频繁重启。
nodemon xxx.js
4.1路由
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数
4.1 路由的匹配过程
每当一个请求到达服务器之后,需要先经过路由的匹配,在匹配时,会按照路由的顺序进行匹配 ( 按照定义的先后顺序、从上向下匹配),如果请求类型和请求的URL同时匹配成功,则Express会将这次请求,转交给对应的function函数进行处理。
4.2 模块化路由
为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到对象上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤如下:
① 创建路由模块对应的js文件
② 调用express.Router0函数创建路由对象
③ 向路由对象上挂载具体的路由
④ 使用module.exports向外共享路由对象
⑤ 使用app.use0函数注册路由模块
4.3 为路由模块添加前缀
// 导入路由模块
const router = require('./webrouter')
// 注册路由模块
// app.use()函数的作用,用来注册全局中间件
app.use('/api',router);
http://127.0.0.1:8081/api/user/1001/zhangsan
5. 中间件
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
Express的中间件,本质上是一个function处理函数,只不过中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res.
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
5.1 全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。
通过调用app.use(中间件函数),即可定义一个全局生效的中间件
const expresss = require('express')
const app = expresss();
const mw = function (req, res, next) {
console.log("将mw注册为全局生效的中间件")
next()
}
app.use(mw);
5.2 全局生效中间件的简化形式
// 定义全局中间件的简化形式
app.use((req, res, next)=>{
console.log("将mw注册为全局生效的中间件")
next()
})
5.3 中间件的作用
多个中间件之间,共享同一份req和res.基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
5.4 局部生效的中间件
不使用app.use()定义的中间件,叫做局部生效的中间件, 只在路由中生效
const expresss = require('express')
const app = expresss();
上例中,局部中间件只在路由"/“中生效,在路由”/user"中不生效
5.5 定义多个局部中间件
const mw1 = function (req, res, next) {
console.log("将mw注册为第一个局部生效的中间件")
next()
}
const mw2 = function (req, res, next) {
console.log("将mw注册为第二个局部生效的中间件")
next()
}
app.get('/user/:id', mw1,mw2,function (req, res) {
console.log(req.url);
const q = req.query;
res.send(q);
})
5.6 使用中间件的五个注意事项
①一定要在路田之前注册中间件
②客户端发送过来的请求,可以连续调用多个中间件进行处理
③执行完中间件的业务代码之后,不要忘记调用next()函数
④为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
⑤连续调用多个中间件时,多个中间件之间,共享req和res对象
5.7 中间件分类
5.7.1 应用级别的中间件
通过app.use() 或app.get() 或app.post(),绑定到app实例上的中间件,叫做应用级别的中间件
5.7.2 路由级别的中间件
绑定到express.Router() 实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到app实例上,路由级别中间件绑定到router实例上。
5.7.3 错误级别的中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式:错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)。
错误级别的路由器必须放在所有路由之后
5.7.4 Express 内置的中间件
① express.static() 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
② express.json() 解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
③ express.urlencoded() 解析URL-encoded格式的请求体数据 (有兼容性,仅在4.16.0+版本中可用)
④ express.json() 和 express.urlencoded() 需要放在路由的前面,若不注册该中间件函数,路由函数中获取到的值为undefined
// 配置解析application/json格式请求数据的内置中问件
app.use(expresss.json( ))
// 配置解析application/ x-www-form-urlencoded格式请求数据的内置中间件
app.use( expresss.urlencoded({ extended: false }))
// 导入路由模块
const router = require('./webrouter')
// 注册路由模块
// app.use()函数的作用,用来注册全局中间件
app.use('/api', router);
//express.static(),通过它,我们可以创建一个静态资源服务器
app.use('/loess', expresss.static('../../file'));
5.7.5 第三方的中间件
非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。
const bodyparser = require('body-parser')
app.use(bodyparser.json);
app.use(bodyparser.urlencoded({extended: false}));
5.7.6 自定义中间件
const expresss = require('express')
const app = expresss();
const qs = require('querystring')
app.use((req, res, next) => {
// 定义一个str字符串,专门用来存储客户端发送过来的请求数据
let str = '';
req.on('data', (chunk) => {
str += chunk;
})
req.on('end', () => {
const body = qs.parse(str);
req.body = body;
next();
})
});
app.post('/user', (req, res) => {
console.log(req.method + "," + req.url);
res.send(req.body);
})
6. 跨域资源共享
6.1 使用CORS跨域资源共享
CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。
浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了CORS相关的HTTP响应头,就可以解除浏览器端的跨域访问限制。
安装cors:npm i cors
const cors = require('cors')
app.use(cors) // 在路由之前注册跨域中间件
6.2 CORS的注意事项
① CORS主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。
② CORS在浏览器中有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如: IE10+、 Chrome4+、FireFox3.5+)
6.3 CORS响应头
6.3.1 Access-Control-Allow-Origin
Access-Control-Allow-0rigin: | *
origin参数的值指定了允许访问该资源的外域URL。
通配符*,表示允许来自任何域的请求。
6.3.2 Access-Control-Allow-Headers
默认情况下,CORS仅支持客户端向服务器发送如下的9个请求头:
Accept.、Accept Language、Content-Language、 DPR、 Downlink. Save-Data、 Viewport-Width.、Width、Content- Type (值仅限于text/plain、multiprt/form-data、 application/x-www-form-urlencoded三者之一)
如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control-Allow-Headers对额外的请求头进行声明,否则这次请求会失败!
6.3.3 Access-Control-Allow-Methods
默认情况下,CORS仅支持客户端发起GET、POST、 HEAD请求。
如果客户端希望通过PUT、DELETE 等方式请求服务器的资源,则需要在服务器端,通过Access-Control-Alow-Methods 来指明实际请求所允许使用的HTTP方法。
6.4 CORS请求的分类
6.4.1 简单请求
同时满足以下两大条件的请求,就属于简单请求:
① 请求方式: GET、 POST、 HEAD三者之一
② HTTP头部信息不超过以下九种字段:无自定义头部字段、Accept.、Accept-Language、 Content-Language、 DPR、Downlink、Save -Data、Viewport-Width、 Width、Content- Type (只有三个值pplication/x www-form-urlencoded、multipart/form-data、 text/plain)
6.4.2 预检请求
只要符合以下任何一个条件的请求,都需要进行预检请求:
① 请求方式为 GET、POST、HEAD之外的请求Method类型
② 请求头中包含自定义头部字段
③ 向服务器发送 了application/jison 格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为"预检请求"。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。
简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。
7. JSONP接口
浏览器端通过script标签的src属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做JSONP.
① JSONP 不属于真正的Ajax请求,因为它没有使用XMLHttpRequest这个对象。
② JSONP仅支持GET请求,不支持POST、 PUT、 DELETE等请求。
如果项目中已经配置了CORS跨域资源共享,为了防止冲突,必须在配置CORS中间件之前声明JSONP的接口。否则JSONP接口会被处理成开启了CORS的接口。示例代码如下:
7.1.1 使用JSONP接口的步骤
① 获取客户端发送过来的回调函数的名字
② 得到要通过JSONP形式发送给客户端的数据
③ 根据前两步得到的数据,拼接出一个函数调用的字符串
④ 把上一步拼接得到的字符串,响应给客户端的script标签进行解析执行
const cors = require('cors')
app.use(cors)
在网页中使用jQuery发起JSONP请求