46 express
Express是基于基于 Nodejs平台,快速、开放、极简的 Web 开发框架
官网地址:https://www.expressjs.com.cn/
作用:使用 Express,我们可以方便、快速的创建 Web 网站的服务器或 API 接口(纯json数据)的服务器。
本质上:express是一个第三方包存在于npm社区中。
二、安装及基本使用
2.1安装
初始化package.json:npm init -y
下包:npm i express
2.2深刻体会一下模块化的好处
我们项目中使用express,所以只下载express即可。而express使用什么我们不关心,由express来进行管理 。
2.3初体验express
原生node 比较麻烦:编码、路径判断的问题、响应js对象:原生node只能返回字符串或buffer(不允许)
const express = require('express')
// console.log( express );
const app = express() //创建一个服务器应用
app.listen( 3000,()=>{
console.log( 'http://localhost:3000 可以访问' )
} )
2.4 app对象
注意:所有的路径都以 / 打头
app.get( 路径,兼听函数 )
兼听客户发送的get请求
callback( req,res )
前端要做的是会向服务器发get请求
除了表单的mthod="post"和ajax( method:'post' ),在浏览器中的其它请求都是get。
mthod="get" ajax( method:'get' ) img:src link:href script:src 这些通通都是get请求。
app.post(路径,兼听函数 )
兼听客户端发送的post请求
表单的mthod="post"和ajax( method:'post' )
2.5response对象
res.send( 字符串|对象 )。
可以发送字符串,也可以发送对象。并且这个方法会根据数据自动设置Content-type。
express框架基于原生http的,express没有覆盖原生httpp。原生的req和res对象上的方法还都可以用。res.end()
res.sendFile( absolute filepath )
把服务器上的某一个文件响应给用户。
app.get('/register',(req,res)=>{
//let filepath = path.join( __dirname,'./pages/03register.html' )
let filepath = path.join( __dirname,'./pages/erha.jpg' )
res.sendFile( filepath )
})
总结:前端用户发的请求,拿的结果完全取决于后端返回的是什么。跟路径没有必然联系(这是比较抽象的一句)。
2.6 request对象
req.query
作用:接收 url地址栏 ?后面的查询字符串参数。简称get的参数
// 前端应该也是必须会拼接url地址。
// http://localhost:3000/login?username=swk&age=20
app.get('/login',(req,res)=>{
console.log( req.query,'默认是一个空对象' ) //:获取get参数。默认是一个空对象
console.log( req.query.username )
if( req.query.uage > 18 ){
res.send('我成年了')
}else{
res.send('呵呵,不要惹熊孩子')
}
})
req.params
专业名称:动态路径(路由)
https://movie.douban.com/subject/34841067/
https://movie.douban.com/subject/26826330/
https://book.douban.com/subject/35315159/
url / :变量名称[参数名称]
比如豆瓣电影的地址: https://movie.douban.com/subject/ ids
而这类的路径上的参数用 req.params 获取 。
往服务器传递的参数都是字符串。由http协议规定的。互联网中传递数据只能传递字符串。
三、工具的使用
nodemon
开发web服务器后端代码,每次修改代码需要重新node一下。
而nodemon工具帮我们这个问题。它是一个全局包( 是个工具 )
使用步骤
-
npm i nodemon -g
-
使用nodemon去运行后端js代码。如 : nodemon app.js
Rest Client
测试接口的工具,简单来说类似于ajax,类似于浏览器地址栏 。
有了此工具那么测试任意请求就非常方便 。
基于vscode的插件而已。
优点:测试记录都有保存留痕
使用步骤
-
安装插件
-
创建以http为后缀的文件
比如:api22.http
-
书写请求地址,发送请求
@url = http://localhost:5000
###
GET {{url}}/login
### 3个#来区分每一个请求
# 也可以写注释
post http://localhost:3000/login
四、路由
1.路由概述
什么是路由?
广义上来讲,路由就是映射关系。
对于我们网络请求中的路由是:每一次请求对应每一个请求处理的函数。
现实中的路由
例如手机或者电话进行拨号可以根据映射关系得到不同的服务。
路由的作用
在web开发中,路由是非常重要的一个体系。访问不同的路由可以得到对应路由的服务。
/login 登录功能
/register 注册功能
/pay 支付功能
2.Express中的路由(Node的路由)
语法:
app.method( 路径地址,callback )
app: 由express() 返回的app实例对象
method:函数的通用名称。 get/post( 定义get路由 ,定义post路由)
路径地址:必须以 “/” 开头
callback:请求处理的函数。准确的说有4个参数。前两个:第1个request对象 ,第2个response对象
完整的路由定义一定是由此语法决定的,缺一不可。
匹配流程:
(1)每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数
匹配成功( 一个请求方法、请求路径地址 )
(2)在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则 Express 会将这次请求,转交给对应的 function 函数进行处理
主要是处理业务,并且把最终的结果响应给前端
(3)如果从上到下有相同的路由,则会匹配第1个。定义相同的路由是没有意义的
//get的路由匹配
app.get('/login',(req,res)=>{
res.send('我匹配到了get请求,并且是login1')
})
app.get('/login',(req,res)=>{
res.send('我匹配到了get请求,并且是login2')
})
//post的路由匹配
app.post('/login',(req,res)=>{
res.send('我匹配到了post请求,并且是login')
})
//动态路由匹配
app.post('/su/:id',(req,res)=>{
res.send('动态路由匹配')
})
3.模块化路由
优化入口文件,否则的话你的项目入口太臃肿。按照项目开发规范来说,应该把所有的路由分离出去。
需求:
教务管理系统:人员管理(学生、老师、管理员)。
学生:添加、删除、修改、查询
老师:添加、删除、修改、查询
未模块化的路由的问题
const express = require('express')
const app = express()
// **需求:**
// 教务管理系统:人员管理(学生、老师、管理员)。
// 学生:添加、删除、修改、查询
// 老师:添加、删除、修改、查询
app.get('/student/add',(req,res)=>{
res.send('添加一个学生')
})
app.get('/student/delete',(req,res)=>{
res.send('删除一个学生')
})
app.get('/student/edit',(req,res)=>{
res.send('修改一个学生')
})
app.get('/student/query',(req,res)=>{
res.send('查看一个学生')
})
/////////////////////////////////////////
app.get('/teacher/add',(req,res)=>{
res.send('添加一个学生')
})
app.get('/teacher/delete',(req,res)=>{
res.send('删除一个学生')
})
app.get('/teacher/edit',(req,res)=>{
res.send('修改一个学生')
})
app.get('/teacher/query',(req,res)=>{
res.send('查看一个学生')
})
app.listen(3000,()=>{
console.log( 'http://localhost:3000' )
})
模块化的路由
语法:
const express = require('express')
const router = express.Router() //实例化一个路由对象
//定义路由
router.get('/login',callback)
router.get('/student/add',callback)
module.exports = router //暴露路由对象
/////////////////////////////////////////////////////////////////
//要在使用的地方引入以上的路由模块
let r = require('自定义路由模块的路径地址')
app.use( r )
//student.js
const express = require('express')
//实例化路由对象
const app = express.Router()
app.get('/student/add',(req,res)=>{
res.send('添加一个学生')
})
app.get('/student/delete',(req,res)=>{
res.send('删除一个学生')
})
app.get('/student/edit',(req,res)=>{
res.send('修改一个学生')
})
app.get('/student/query',(req,res)=>{
res.send('查看一个学生')
})
//暴露路由
module.exports = app
app.use的另一个语法
app.use( ‘/前缀’,路由 )
//teacher.js
app.use( '/teacher',teacherRouter )
五、中间件
中间件(Middleware ),特指业务流程的中间处理环节( 指路由当中的处理层:指的就是函数 )。本质上中间件就是函数。
中间件其实就是一个特殊的路由、升级版的路由。中间件函数都会被所有的请求匹配到。
好处:提升我们的开发效率 。
现实中的中间件
我们可以把中间件函数比作工厂中的车间
说明中间件的原理。
每一个车间都是独立的功能 。各司其职,谁也别影响谁。
特点:在一个车间(中间件中)处理完了,必须往下走next,必须 匹配一个最终的路由并且响应结果数据。
中间件执行流程
使用中间件
1.语法
中间件没有特殊情况,一般都是在所有的路由前面 。
app.use( [前缀,]中间件函数 )
callback( req,res,next )
中间件和路由中的req是共用 的。
何时加前缀?某些不需要匹配到中间件,有些请求需要匹配到中间件,所以可以为某些路由(中间件)添加一些前缀
2.自定义一个中间件
需求:后端要获取用户的请求时间 。
未使用中间件
const app = express()
const timeStamp = require('time-stamp')
// 后端要获取用户的请求时间 。
// console.log( timeStamp('YYYY年MM月DD日 HH:mm:ss') )
app.get('/login',(req,res)=>{
let times = timeStamp('YYYY年MM月DD日 HH:mm:ss')
res.send(`login访问时间是:${times},后端想要统计的`)
})
app.get('/register',(req,res)=>{
let times = timeStamp('YYYY年MM月DD日 HH:mm:ss')
res.send(`register访问时间是:${times},后端想要统计的`)
})
使用中间件优化好的
const timeStamp = require('time-stamp')
// 后端要获取用户的请求时间 。
// console.log( timeStamp('YYYY年MM月DD日 HH:mm:ss') )
// let times = ''
app.use( (req,res,next)=>{
// console.log('匹配到了中间件函数')
req.times = timeStamp('YYYY年MM月DD日 HH:mm:ss')
next()//往下走,去找真正要匹配的路由规则
} )
app.get('/login',(req,res)=>{
// console.log(times);
res.send(`login.通过中间件往req对象上绑定了times属性。所以时间为 :${req.times}`)
})
app.get('/register',(req,res)=>{
res.send(`register 通过中间件往req对象上绑定了times属性。所以时间为 :${req.times}`)
})
中间件种类
错误中间件
404和逻辑错误
内置中间件
static
urlencoded
json
第三方中间件
server-icon
svg-captcha
六、文件上传
七、cookie
介绍
特点
应用场景
实现原理
八、session
简介
特点
应用场景
实现原理
九、模板引擎
十、express脚手架
十七、koa框架
前后端数据交互总结
| 请求方法 | 编码格式 | 前端要传输的数据格式 | 后端如何获取 | 应用场景 |
|---|---|---|---|---|
| GET | url地址后面(querystring) | url?key1=value1&key2=value2 | 不需要中间件:req.query | 获取数据 |
| POST | applicaion/x-www-form-urlencoded | form-data: key1=value1&key2=value2 | express.urlencoded( { extend:true } ) | 提交数据 |
| POST | applicaion/json(只能通过ajax) | request-payload: '{ "key1":"value1","key2":"value2" }' | express.json() | |
| POST | mutilpart/form-data(可以使用表单) | 文件流 | 文件上传 | |
| DELETE | 同post | 删除数据 | ||
| PUT | 同post | 更新数据 |

浙公网安备 33010602011771号