app.use()
use是使用,到底使用了什么东西呢
app.use() 最简单用法
app.js
const express = require('express')
const app = express()
app.use((request,response,next)=>{
console.log(request.url)
response.write('hi')
next() //如果不next 不会执行下一个use
})
//本来是用response.send()的, 但是不能两次send,所以改用write,这是一个流,所以可以写入多次
app.use((request,response,next)=>{
console.log(2)
response.write('hi')
next()
})
app.use((request,response,next)=>{
response.end() //end表示数据写完了
next() //这个next可以省略 因为在最后一步了。
})
app.listen(3000,()=>{
console.log('正在listen 3000')
})
Express的编程模型
- 每一次请求的时候(比如在localhost:3000刷新一次),就会向express服务器发送一次请求
- 与此同时,express会构造出一个response对象,next函数,连同这一次的请求request,这三个东西都发给app.use()里的function
app.use(``function``(req,res,next){})
- 图中的·启动·意思是:express会在每次请求进来时,做一写准备工作,就是这个启动程序
- 启动完之后就会进入第一个fn1,然后fn2,然后fn3,如果中间又调用了app.use(),又会把fn插入进去(橙色部分),这样执行下去,直到结束(会执行express的结束程序,一般是一些清理工作)
- 每一个请求都是上面这些顺序
- 每一个fn可以做什么(三种常用操作)
- 读request 读一下用户请求的数据
- 写response 写一下response里面的内容,比如用response.write()写入, response.end()写入结束
- 调用next() 表示这个fn的当前任务已经完成
中间件
回到上面的编程模型,fn就是中间件,因为它是被插入到启动和结束中间的物件
其实在上面的代码中
app.use((request,response,next)=>{
console.log(request.url)
response.write('hi')
next() //如果不next 不会执行下一个use
})
这个就是我们的中间件,是我们自己定义的, 还有一些是别人写好的
比如express手脚架中的app.js:
我们可以改写成
const fn1 =logger('dev')
app.use(fn1)
const fn2 = express.json()
app.use(fn2)
就跟我们的没多大区别了,就看上面的五行代码,其实就是express的编程模型,fn1,fn2这样用下去。
这样用有什么好处呢
优点:模块化
- 这种模型(express编程模型,fn1,fn2这样)使得每个功能都能通过一个函数实现
- 然后通过app.use将这个函数整合起来
- 如果把函数放到文件或npm里,就实现了模块化
写一个独立的模块,任何人访问的时候,都会把他的url打印出来
logger.js
const logger = function (req,res,next){
console.log(req.url)
next()
}
就这么简单就写完了,怎么使用呢:
访问3000端口
就打印出来了根目录,但是我根本不用担心logger是怎么实现的,因为它是中间件
改进一下:加一个参数,可以传入一个前缀
logger.js
const logger = (prefix)=>{
return function (req,res,next){
console.log(prefix + req.url)
next()
}
}
module.exports = logger
使用的时候就 app.use(logger(hasson's
))
这就是中间的好处,你只要把它放在中间,然后让它执行,你就根本不用去管它
路由
同样的,express的编程模型使得路由功能变得非常简单。
实现:用户访问三个不同路径是得到三个不同的字符串
app.use((req,res,next)=>{
if(req.path === '/' && res.method === 'get'){
res.send('根目录')
}
next()
})
app.use((req,res,next)=>{
if(req.path === '/aaa'){
res.send('这是aaa')
}
next()
})
app.use((req,res,next)=>{
if(req.path === '/bbb'){
res.send('这是bbb')
}
next()
})
这样可以看到,我们可以把每个模块单独得拎出来,比如说我们可以把/aaa的use写成之前的logger.js一样,所以与其说express是一个web框架,倒不如说它是一个专门做中间件的框架,它使得你的所有功能都可以以中间件的形式插入到app里面。
上面的功能有一些更好用的写法(API糖)
app.use('/aaa',fn)
app.get('/aaa',fn)
app.post('/aaa',fn)
app.route('/xxx').all(f1).get(f2).post(f3)
用这些API改进一下:
app.use('/xxx', (req, res, next) => {
res.send('这是xxx');
next();
});
app.get('/aaa',(req,res,next)=>{
res.send(`这是aaa`)
next()
})
app.route('/bbb')
.all((req,res,next)=>{
res.write(`all`)
next()
}) //不管什么方法 get post put 都会执行回调
.get((req,res,next)=>{
res.write(` bbb`)
res.end()
next()
})
.post()