获取前端发送的内容
导入模块
1 2 3 4 5 6
| const express = require('express')
const app = express()
const port = 3000
|
使用GET方法
app.get(path,(req,res)=>{})
1 2 3 4 5 6 7
| app.get('/', (req, res) => { res.send({name:'libai518',age:21,gender:'男'})
console.log(req.query) })
|
使用POST方法
app.post(path,(req,res)=>{})
1 2 3
| app.post("/user",(req,res)=>{ res.send('请求post成功') })
|
URL动态参数
app.get('.//:param',function(req,res){})
,:param
表示是一个参数,在请求url
则请求http://127.0.0.1/user/1/10
,page=1,count=10
,即带有分页书条数。
1 2 3 4 5 6
| app.get('/user/:page/:count',(req,res)=>{
res.send(req.params) console.log(req.params) })
|
启动服务器
1 2
| app.listen(port, () => console.log(`Example app listening on port ${port}!`))
|
托管静态资源
托管一个静态资源
在托管静态资源的时候,在客户端打开此资源文件夹的是看不到文件夹名的,看到的只有一个/
简单来说就是对外开放了一个文件夹,客户端可以访问到某个文件夹内的资源,一般用来存放HTML
、JS
、CSS
、图片等。
1 2 3 4 5 6 7 8 9 10
| const express = require('express') const path = require("path") const app = express() const port = 3000
const Path = path.join(__dirname,"./public/")
app.use(express.static(Path))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
|
托管多个静态资源
在托管多个资源时,是存在优先级的,因为js
是解释性语言,优先级从上往下。
如果客户端请求一个index.html
文件,没有指定某个静态资源路径,那nodejs
就会从第一个静态资源库寻找有没有index.html
,如果没有,则继续下一个静态资源库寻找index.html
文件,直到全部静态资源都找完都没有才结束查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const express = require('express') const path = require("path") const app = express() const port = 3000
const Path = path.join(__dirname,"./public/")
app.use(express.static(Path)) app.use(express.static("./node_modules/"))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
|
给托管资源添加访问前缀
由于客户端在访问静态资源时是看不到根文件夹名字的,我们可以给该文件夹添加一个访问前缀,这样可以更方便操作路由以及前期调试。
使用方法
在原基础上添加一个路径
参数即可。
1 2
| app.use(express.static(Path)) app.use("/abc",express.static(Path))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const express = require('express') const path = require("path") const app = express() const port = 3000
const Path = path.join(__dirname,"./public/")
app.use(express.static(Path)) app.use(express.static("./node_modules/"))
app.use("/abc",express.static(Path))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
|
路由
路由的匹配
每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。
在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的URL同时匹配成功,则Express会将这次请求,转
交给对应的function函数进行处理。
)
- 按照定义的先后顺序进行匹配
- 请求类型和请求的UL同时匹配成功,才会调用对应的处理函数
路由模块化
将路由抽离为单独模块的步骤如下:
- 创建路由模块对应的
js
文件
- 调用
express.Router()
函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用
module.exports
向外共享路由对像
- 使用
app.use()
函数注册路由模块
路由主方法
最重要的步骤就是要注册路由模块,简单来说就是把路由设置分化成若干个模块,然后在主方法内注册若干个模块,这样在客户端请求url
时,主方法会调用其他路由模块进行查找,可以降低耦合性。
1 2 3 4 5 6 7 8 9 10 11
| const express = require('express') const app = express()
const port = 3000
const router = require('./router/01router')
app.listen(port, () => { console.log(`Example app listening on port ${port}!`) })
|
路由分模块
最重要的步骤就是要对外导出对象
,不然主方法内是找不到分模块的方法的。
在哪个模块要实现router.method()
方法,哪个模块就要创建路由对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const express = require("express")
const router = express.Router()
router.get("/user",(req,res)=>{ res.send("这是get请求的路由") })
router.post("/user",(req,res)=>{ res.send("这是post的请求路由") })
module.exports =router
|
中间件
中间件的五个注意事项:
-
一定要在路由之前
注册中间件
-
客户端发送过来的请求,可以连续调用多个
中间件进行然理
-
执行完中间件的业务代码之后,不要忘记调用next()函数
-
为了防止代码逻辑混乱
,调用next()
函数后不要再写额外的代码
-
连续调用多个中间件时,多个中间件之间,共享req
和res
对象
局部中间件
不使用app.use()
定义的中间件都叫局部生效的中间件
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const express = require('express') const app = express()
const port = 3000
const t1 = (req,res,next)=>{ console.log('调用了局部中间件1') next() } const t2 = (req,res,next)=>{ console.log('调用了局部中间件2') next() }
app.get('/',[t1,t2], (req, res) => {
console.log('这是GET路由控制!') res.send(`这是GET路由控制!`) })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
全局中间件
执行过程:
执行顺序全局中间件app.use()
、全局中间件app.use()
,再执行路由app.get()
,由于JS
是解释性语言,中间件的执行顺序由上到下
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| const express = require('express') const app = express()
app.use((req,res,next)=>{ const time = Date.now() req.starttime = time console.log('这是中间件1') next() })
app.use((req,res,next)=>{ const time = Date.now() req.starttime = time console.log('这是中间件2') next() })
app.get('/', (req, res) => { console.log('路由在中间件执行后执行') res.send('这是get请求'+req.starttime) })
app.listen(3000,()=>{ console.log('http://127.0.0.1:3000') })
|
next()函数的作用
next()
函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
)
中间件的分类
应用级别的中间件
通过app.use()
或app.get()
或app.post()
,绑定到app
实例上的中间件,叫做应用级别的中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const express = require('express') const app = express()
const port = 3000
app.use((eq,res,next)=>{ next() })
app.get('/',t1,(req,res)=>{ res.send('这是GET请求') })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
路由级别的中间件
绑定到express.Router()
实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到app
实例上,路由级别中间件绑定到router
实例上,代码示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const express = require('express') const app = express() const router = express.Router()
const port = 3000
router.use((req,res,next)=>{ console.log('Time:'+Date.now()) next() }) app.use('/',router)
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
错误级别中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式:错误级别中间件的function
处理函数中,必须有4
个形参,形参顺序从前到后,分别是**(err
,req,res,next)**
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const express = require('express') const app = express()
const port = 3000
app.get('/',(req,res)=>{ throw new Error('服务器内部出错') res.send('到上一步已经停止执行了出错了,这步不执行') })
app.use((err,req,res,next)=>{ console.log('发生了错误!'+ err.message) res.send('Error: '+ err.message) })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
Express内置的中间件
自Express4.16.0
版本开始,Express内置了3个
常用的中间件,极大的提高了Express
项目的开发效率和体验:
express.static
快速托管静态资源的内置中间件,例如:HTML文件
、图片
、CSS
样式等(无兼容性)
express.json
解析JSON
格式的请求体数据(有兼容性,仅在4.16.0+
版本中可用)
express.urlencoded
解析URL-encoded
格式的请求体数据(有兼容性,仅在4.16.0+
版本中可用)
1 2 3 4
| app.use(express.json())
app.use(express.urlencoded({extended:false}))
|
express.static()的使用
[path]
表示前缀路径,在访问该路径的时候要加上前缀路径。
比如app.use('abc',express.static('./node_modules/'))
,那我在访问的路径应该是http://127.0.0.1/abc/
这样的。
1
| app.use( [path ,] express.static('./node_modules/'))
|
express.json()
可以接受到客户端发送的json数据,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const express = require('express') const app = express()
const port = 3000
app.use(express.json())
app.get('/',(req,res)=>{ console.log(req.body) res.send('ok') })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
express.urlencoded()
express.urlencoded()
和express.json()
的用法基本一样的,只是用于解析的中间件不一样,其他是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const express = require('express') const app = express()
const port = 3000
app.use(express.urlencoded({extended:false}))
app.get('/',(req,res)=>{ console.log(req.body) res.send('ok') })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
第三方的中间件
非Express
官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
例如:在express@4.16.0
之前的版本中,经常使用body~parser
这个第三方中间件,来解析请求体数据。使用步骤如下:
- 运行
npm install body-parser
安装中间件
- 使用
require
导入中间件
- 调用
app.use()
注册并使用中间件
注意:Express
内置的express.urlencoded
中间件,就是基于body-parser
这个第三方中间件进一步封装出来的。
body-parser
中间件和Express内置urlencoded
用法非常像。
1 2 3 4 5 6 7
| const parser = require('body-parser') app.use(parser.urlencoded({extended:false}))
app.post('/user',(req,res)=>{ console.log(req.body) res.send('ok') })
|
自定义中间件
需求与实现步骤
自己手动模拟一个类似于express.urlencoded
这样的中间件,来解析POST提交到服务器的表单数据
。
实现步骤:
- 定义中间件
- 监听
req
的data
事件
- 监听
req
的end
事件
- 使用
querystring
模块解析请求体数据
- 将解析出来的数据对象挂载为
req.body
- 将自定义中间件封装为横块
监听req
和data
事件
在中间件中,需要监听req
对象的data
事件,来获取客户端发送到服务器的数据。
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切制后
,分批发送到服务器
。所以data
事件可能会触发多次,每一次触发data
事件时,获取到数据只是完整数据的一部分
,需要手动对接收到的数据进行拼接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const express = require('express')
const app = express()
const port = 3000
app.use((req,res,next)=>{ let str='' req.on('data',(chunk)=>{ str+=chunk }) })
app.listen(port, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
将解析出来的数据对象挂载为req.body
上游的中间件和下游的中间件及路由之间,共享同一份req
和res
。因此,我们可以将解析出来的数据,挂载为req
的自定义属性,命名为req.boyd
,供下游使用。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| app.use((req,res,next)=>{ 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)=>{ res.send(req.body) })
|
中间件模块化
- 将中间件函数剪切到
index.js
文件
- 导入中间件所需要的模块
- 再抛出中间件对象
自定义中间件主方法.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const express = require('express') const qs = require('querystring')
const app = express()
const table = require('./解析表单数据')
app.use(table)
app.post('/user',(req,res)=>{ res.send(req.body) })
app.listen(3000, ()=>{ console.log('服务器已启动 http://127.0.0.1:3000') } )
|
TableData.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const express = require('express') const qs = require('querystring')
const app = express()
const TableData=app.use((req,res,next)=>{ let str='' req.on('data',(chunk)=>{ str+=chunk }) req.on('end',()=>{ const body = qs.parse(str) req.body =body next() }) })
module.exports =TableData
|