共计 7122 个字符,预计需要花费 18 分钟才能阅读完成。
这几天天天搞到这么晚,我看明天的内容看起不多啊,不晓得为什么学着学着就到了这么晚。明天的内容还是有点多哈,有点自我矛盾了,再次一一道来。
1.
首先明天先看到路由的概念,什么叫做路由?
路由就是映射关系,在 express 中路由指的是客户端申请和服务器处理函数的映射关系,路由有三局部组成:申请类型、申请 url 和处理函数。
app.get(url,callback) 其实就跟咱们后面所说的监听事件一样一一样的。
const express = require('express')
const app = express()
app.get('/', (req, res) => {res.send('收到 get 申请')
})
app.listen(80, () => console.log('express server running at http://127.0.0.1'))
这就是一个最简略的路由。路由的匹配过程,每当一个申请达到服务器器后,须要先通过路由匹配,当申请类型和 url 匹配胜利后才会调用前面的申请函数。、
用法
最简略的用法就是像咱们下面那样间接挂在实例上,这也是不举荐的,因为一个申请就要挂一个很麻烦很繁琐。
迷信的办法应该是创立路由模块。
分为五个步骤:
别离是创立路由 js 文件、调用 express.Router 创立路由对象、挂载路由、向外导出路有对象最初咱们的入口文件须要导入,在通过 app.use 去注册
// 1. 导入 express
const express = require('express')
// 2. 创立路由对象
const router = express.Router()
// 3. 挂载路由
// 3.1 挂载路由获取用户的信息
router.get('/user/:id', (req, res) => {res.send(req.params)
})
// 3.2 挂载路由承受用户发送的申请
router.post('/post', (req, res) => {res.send('post 胜利')
})
// 4. 向外共享路由成员
module.exports = {
express,
router
}
const express = require('./02 模块化路由')
const app = express.express()
// 注册路由
app.use(express.router)
app.listen(80, () => console.log('express server running at http://127.0.0.1'))
这里说一下 app.use 昨天也看到了,他其实就是一个用来注册全局中间件的。而后咱们还能够为路由挂载前缀,也是通过 app.use 来增加办法同昨天根本一样
2.
中间件
指的是业务流程的两头解决环节。
就是当客户申请达到服务器后,可间断调用多个中间件对这个申请进行预处理,最初通过路由发送进去。
中间件的实质是一个函数根路有相似然而多了一个参数,next 参数。
next 是一个函数它的作用就是实现多个中间件间断调用的要害,把流转关系转给下一个中间件或者路由,每个中间件都有一个 next 一个转下去转到路由没有了就响应给客户端了。
2.1
咱们先看到全局失效的中间件,意思就是客户发动的任何申请,他都会触发,间接通过 app.use 来注册即可
const express = require('express')
const app = express()
// 中间件
const mw = function(req, res, next) {// res.send('这是中间件环节')
console.log('这是中慢慢环节')
next()}
// 通过 app。use 定义为全局失效的中间件
app.use(mw)
app.get('/user', (req, res) => {res.send('这是 get 申请')
})
app.post('/post', (res, req) => {res.send('这是一个 post 申请')
})
app.listen(80, () => {console.log('http://127.0.0.1');
})
中间件的作用:
多个中间件共享同一个 res 和 req,所以能够在上游的中间件定义好这些对象,上游间接用包含路由也能够用
怎么来定义多个全局中间件,间接通过 app.use 定义多个即可就像昨天所说的托管动态资源,有多个目录就注册多个
2.2
部分中间件
不是用 app.use 只对局部的路由无效,路由 的参数规定 也产生了扭转
const express = require('express')
const app = express()
const mw = function(req, res, next) {req.time = Date.now()
next()}
app.get('/', mw, (req, res) => {res.send('部分失效' + req.time)
})
app.get('/user', (req, res) => res.send('没有失效') + req.time)
app.listen(80, ()=> {console.log('http://127.0.0.1');
})
定义多个部分中间件
写多个函数过后在参数这里能够用逗号隔开,也能够间接写一个数组
有一个注意事项:就是肯定要在路由之前去注册中间件,不然路由执行完了谁还来执行中间件。
2.3
中间件的分类
①利用级别中间件
就是通过 get、post、use 绑定到 app 上的中间件
②路由级别中间件
就是在咱们方才的路由模块外面来交叉的一个中间件
③谬误级别中间件
这个有点说法
它是专门用来捕捉错误信息的而且形参变为了四个
他也是惟一一个卸载路由前面的中间件
const express = require('express')
const {rename} = require('fs')
const app = express()
app.get('/', (req, res) => {
// 1. 人为抛出一个谬误,一旦有错前面的响应就不会执行了
throw new Error('服务器外部产生谬误')
res.send('我不能执行进去')
})
// 2. 谬误中间件
app.use((err,req,res,next) => {
// 2.1 向服务器打印谬误
console.log(err.message);
// 2.2 向客户端发送谬误
res.send(err.message)
// 这样做 益处就是,后面如果产生了谬误导致了整个服务器曾经解体了,什么都执行不了了,这样一来,就能够失常输入错误信息,失常执行前面代码
})
app.listen(80, () => console.log('express server running at http://127.0.0.1'))
④内置中间件
三个内置的中间件别离是 express.static 这个曾经说过了后面
express.json 这是拿来解析 json 格局数据的
express.urlencoded 这是拿来解析 urlencoded 格局数据的
前面两个个别会配合 req.body 来拿申请体数据再给他们拿来解析了
const express = require('express')
const app = express()
// 留神这是中间件 所以必须配置到路由之前
app.use(express.json())
app.use(express.urlencoded({extended : false}))
app.post('/', (req, res) => {
// 通过 req.body 能够拿到申请体数据
// postman 在测试的时候抉择 body 外面的 raw 再把 text 抉择 json 就能够发送 json 数据了
console.log(req.body);
// 没有解析之前对于 json 数据是 undefined
})
// 测试 urlencoded 数据体
// 这个数据体的格局是 x -www-form-urlencoded
// 固定写法
app.post('/user', (req, res) => {
// 没解析前时空对象
console.log(req.body);
})
app.listen(80, () => console.log('express server running at http://127.0.0.1'))
⑤第三方中间件 间接 npm 装置导入通过 app.use 注册即可应用
2.4
自定义中间件
这里做一个案例自定义一个相似于 express.urlencoded 性能的中间件能够解析申请体数据
const express = require('express')
const app = express()
// 4. 利用 node 外面的一个内置模块解析申请体数据,在 node 外面内置了一个 querystring 模块是专门用来解决查问字符串的,这个模块提供的
// parse()函数能够把查问字符串转换为对象
const qs = require('querystring')
// 1. 定义中间件
app.use((req, res, next) => {
// 2. 监听 data 事件,因为既然是服务器,那么必定会接管到癞子客户端的申请,如果有时候申请量过大,就会分批次传给服务器数据,所以 data 事件可能触发屡次
// 就须要把每一次的数据最初拼接起来
let str = ''req.on('data', chunk => {str += chunk})
// 3.req 的 end 事件当申请体接管结束会主动登程 end 事件能够在这里解决残缺的申请体数据
req.on('end', () => {console.log(str);
str = qs.parse(str)
console.log(str);
// 5. 解说洗出来的对象给到 req.body
req.body = str
next()})
})
app.post('/', (req, res) => {res.send(req.body)
})
app.listen(80, () => console.log('http://127.0.0.1'))
而后将自定义中间件进行了一个模块化
// 4. 利用 node 外面的一个内置模块解析申请体数据,在 node 外面内置了一个 querystring 模块是专门用来解决查问字符串的,这个模块提供的
// parse()函数能够把查问字符串转换为对象
const qs = require('querystring')
// 因为他人导入进来是间接注册应用所以能够把 app 开服务器等一些多余的代码省略就保留 app.use 外面的
const bodyParse = (req, res, next) => {
// 2. 监听 data 事件,因为既然是服务器,那么必定会接管到癞子客户端的申请,如果有时候申请量过大,就会分批次传给服务器数据,所以 data 事件可能触发屡次
// 就须要把每一次的数据最初拼接起来
let str = ''req.on('data', chunk => {str += chunk})
// 3.req 的 end 事件当申请体接管结束会主动登程 end 事件能够在这里解决残缺的申请体数据
req.on('end', () => {console.log(str);
str = qs.parse(str)
console.log(str);
// 5. 解说洗出来的对象给到 req.body
req.body = str
next()})
}
module.exports = bodyParse
const bodyParse = require('./ 自定义中间件模块化')
const express = require('express')
const app = express()
app.use(bodyParse)
app.post('/', (req, res) => {// res.send('收到 get 申请')
console.log(req.body);
})
app.listen(80, () => console.log('express server running at http://127.0.0.1'))
3.
咱们持续看到用 express 来写接口
分为了三个步骤
创立根本服务器、创立 api 路由模块、编写 get 接口
这是路由模块
// 2. 写 api 路由模块 就是将路由模块化 因为那边引入进来须要用 use 来注册同时挂载 api 前缀
const express = require('express')
const router = express.Router()
// 3. 编写 get 接口
router.get('/get', (req, res) => {
// 3.1 首先拿到用户传过来的数据
let data = req.query
// 3.2 把数据发送给客户端
res.send({
status : 0, // 0 示意胜利 1 示意失败
msg : 'get 申请胜利',
data : data // 把数据返回给客户端
})
})
// 4. 编写 post 接口
router.post('/post', (req, res) => {
// 4.1 客户端发过来的数据
let data = req.body
res.send({
status : 0,
msg : 'post 申请胜利',
data : data
})
})
module.exports = router
其实次要就是通过 req 的那几个属性拿到数据后,再通过 send 办法发给客户端,上面是入口文件次要就是开启服务器,而后解析下数据
// 1. 创立根本 web 服务器
const express = require('express')
const app = express()
// 2.1 导入路由模块 并挂载前缀
const router = require('./router')
// 4.2 注册内置中间件 不然 req.body 解析不进去
app.use(express.urlencoded({extended : false}))
// 5.cors 解决跨域
const cors = require('cors')
app.use(cors())
app.use('/api', router)
app.listen(80, ()=> {console.log('http://127.0.0.1');
})
有些货色要把前面看了才晓得哈我只是先拿上来了。
4.
cors 和 jsonp
咱们方才这个案例其实是有 bug 的,就是有跨域的问题,咱们创立一个 html 文件通过 button 来获取数据这个时候就会因为协定不同而被同源策略组织。
咱们后面也说过解决跨域一个是 cors 一个是 jsonp,这里必定不能用 jsonp 因为他只反对 get,那么怎么来用 cors 呢?
间接三部曲装置导入加注册就解决了跨域问题了,就这么简略。
4.1
什么是 cors
就是由一系列 http 响应头组成,同源策略碰到这个头就会解除限制。
cors 个别是在服务器进行配置,客户端不须要。
上面是一些理解性内容
响应头部:
第一个 res.setHeader(‘Access-Control-Allow-Orign’,‘http:wwwssss。聪慧、’)
这是示意只容许前面这个网站的域来拜访,如果为 * 那就示意容许任何域来拜访了
第二个是后面的根底上为 Allow-Headers
咱们的 cors 默认值只有 9 个申请头如果超出了这个九个头就必然失败申请,在这个九个之外的能够通过这个代码来增加上来
第三个后面的根底上 -Methods
cors 默认只反对 get post head 除此之外的须要用这个来设置。
4.2
当初不是理解内容了。
cors 申请分类
大体上分为简略申请和预检申请。
什么叫做简略申请
满足两个条件:
一个是申请形式在默认的三个之内,一个是 http 申请头不能超过默认的九个
什么是预检申请
三个条件达到其中一种都是
一个是申请头在九个之外,一个是申请形式在三个之外,还有一个就是发送过去的数据是 json 数据
那么他们的区别是什么呢
很简略,简略申请只会发送一次申请,而预检申请会发送两次申请,为什么?
因为预检申请会在服务器与客户端正是连贯之前,提前发一个 option 的申请作为预检,看服务器是否跟这个格局的申请相连接,只有申请胜利了才会开始正式申请,携带实在数据。
5.
明天最初一个内容 jsonp 接口
首先要留神一下,如果说曾经配置了 cors 那么必须在配置 cors 之前去申明 jsonp 接口,不然会错乱的。
做这个接口之前咱们先来回应一下 jsonp 的一个常识,首先它是来解决跨域的,咱们通过 script 标签把函数传进来再去调用接口这种形式就叫 jsonp
// 1. 创立根本 web 服务器
const express = require('express')
const app = express()
// 2.1 导入路由模块 并挂载前缀
const router = require('./router')
// 4.2 注册内置中间件 不然 req.body 解析不进去
app.use(express.urlencoded({extended : false}))
// 6.jsonp 接口必须写在 coes 之前
app.get('/api/jsonp', (req, res) => {
// 6.1 获取回调函数的名字
let fn = req.query.callback
// 6.2 定义你要发送回去的数据对象
let data = {name : '张三', age : 15}
// 6.3 模仿函数调用
let fnDiao = `${fn}(${JSON.stringify(data)})`
// 6.4 数据返回回去
res.send(fnDiao)
})
// 5.cors 解决跨域
const cors = require('cors')
const {json} = require('body-parser')
app.use(cors())
app.use('/api', router)
app.listen(80, ()=> {console.log('http://127.0.0.1');
})