## ==2.express基础==
### 2.1 express简介
- express是基于==node==平台的,快速,开放的,极简的web开发框架
- JavaScript ---> jQuery
- node+http ---> express
- 官网地址:https://www.expressjs.com.cn/
- 作用:使用Express,我们可以方便、快速的创建==web网站服务器==或==API接口(纯json数据)服务器==
- 本质上:==express是一个第三方包存在于npm社区中==
### 2.2 express基础使用
#### 2.2.1 express安装
- 初始化项目、安装express
~~~js
1.创建项目管家
npm init -y
2.下载express
npm i express --save
~~~
#### 2.2.2 express基础使用
- 使用express创建web服务器
~~~js
//1.引入express包
const express = require("express");
console.log(express); //[Function: createApplication]
//2.创建web服务器,express:[Function: createApplication] 创建应用对象
const app = express();
//3.监听端口 ,回调函数,端口开放成功时调用,给开发人员看的
app.listen(3000,()=>{
console.log("3000端口开放成功,现在可以开始访问");
})
~~~
- express响应
~~~js
//4.响应 app.method(url,callback)
//method:请求方法,get,post,delete,put
//url 请求地址,必须以/开头
//callback:回调函数,响应请求
/*express优势:
1.代码更优雅,一个请求一个方法
2.设置请求url /(根):表示首页 http://localhost:3000
3.express响应用的是send方法
a.返回的数据类型更灵活,根据数据类型自定义设置响应头的Content-type
b.默认text/html;charset=utf-8,
json : application/json; charset=utf-8
*/
//用户发起是get请求,请求的url是/login 需要同时满足这两个条件才能触发这个请求
app.get("/login",(req,res)=>{
//req:request 请求对象
//res:response 响应对象
res.send({name:"web"})
})
app.get("/register",(req,res)=>{
//req:request 请求对象
//res:response 响应对象
res.send("注册成功")
})
app.get("/",(req,res)=>{
res.send("<h1>首页</h1>")
})
~~~
## 3.express对象
### ==3.1 app对象==
- 使用express实例出来的对象
- 方法:app.get() / app.post() / app.delete() / app.put()
#### 3.1.1 get
- 什么是get请求
~~~js
直接在浏览器地址栏直接访问地址:回车
页面的所有src都是get请求 img / video / audio / script
页面的所有href也是get请求 a / link
form请求也可以设置get请求
ajax也可以发送get请求
~~~
- 作用:监听用户发起的get请求,然后去响应
- 语法:app.get(path,callback)
- 参数
- path:必需。路径,必须/开头
- callback:回调函数,匹配到这个请求执行的回调函数,至少有两个参数
- req:request 对象
- res:response对象
~~~js
//4.定义请求(监听) 语法:app.get(path,callback)
//http://localhost:3000/login?username=www&password=123
app.get("/login",(req,res)=>{
res.send("get发起的登录请求");
})
~~~
- ==注意:get请求请求参数会直接拼接在地址栏上,以查询字符串格式传递给后台,不安全==
#### 3.1.2 post
- 什么是post请求
~~~js
form请求可以设置post请求 (目前只能通过form演示post请求)
ajax也可以发送post请求
~~~
- 作用:监听用户发起的post请求,然后去响应
- 语法:app.post(path,callback)
- 参数
- path:必需。路径,必须/开头
- callback:回调函数,匹配到这个请求执行的回调函数,至少有两个参数
- req:request 对象
- res:response对象
~~~js
//5.定义请求(监听) 语法:app.post(path,callback)
app.post("/login",(req,res)=>{
res.send("post发起的登录请求");
})
~~~
- ==注意:post请求参数,以请求体的方式传递到后台,相对安全==
- ==get请求和post请求的区别==
~~~js
get:
一般用于请求数据
get参数会直接拼接在url的后面,隐蔽性差,不安全
get参数有长度限制
get支持缓存
post:
一般用于提交数据
post参数在请求体中传递,隐蔽性较强,相对安全
post参数没有长度限制
post不支持缓存
~~~
### ==3.2 response对象==
#### 3.2.1 send
- 作用:从服务器返回数据到客户端
- ==语法:res.send(string/object)==
- 参数
- string:返回普通字符串,默认当作html进行渲染,text/html;charset=utf-8
- object:返回对象,默认当作application/json形象渲染
- 基础使用
~~~js
//4.定义请求 /:根 http://localhost:3000
app.get("/",(req,res)=>{
/*
语法:res.send(string/object)
- string:返回普通字符串,默认当作html进行渲染,text/html;charset=utf-8
- object:返回对象,默认当作application/json形象渲染
*/
res.send("我是一个字符串:"+"<h1>首页</h1>");
})
~~~
- ==注意:每一个请求一定会有响应,只能响应一次==
~~~js
//4.定义请求 /:根 http://localhost:3000
app.get("/",(req,res)=>{
/*
语法:res.send(string/object)
- string:返回普通字符串,默认当作html进行渲染,text/html;charset=utf-8
- object:返回对象,默认当作application/json形象渲染
*/
res.send("<h1>首页</h1>"+"我是一个字符串");
//每一个请求一定会有响应,只能响应一次
// Cannot set headers after they are sent to the client
res.send({"name":"我是对象"});
})
~~~
- 其他的数据类型还是需要自己设置响应头
~~~js
app.get("/login",(req,res)=>{
/*
如果返回的是字符串和对象,会默认设置响应头,但是其他的数据类型还是需要自己设置响应头
原生node:res.writeHead(状态码,{"Content-type":"文件类型"})
express:res.setHeader("Content-type","文件类型")
*/
//设置响应头
res.setHeader("Content-type","image/jpeg");
//读取图片内容
let img = fs.readFileSync(path.join(__dirname,"img/a.jpg"));
//返回一张图片到客户端
res.send(img);
})
~~~
==注意:不需要刻意去记文件类型,95%以上返回的数据都是字符串或对象==
- 文件类型表:[HTTP Content-type 对照表 (oschina.net)](https://tool.oschina.net/commons)
#### 3.2.2 sendFile
- 作用:响应一个文件给客户端
- ==语法:res.sendFile(absolutefilepath)==
- 参数
- absolutefilepath:文件路径(绝对路径)
~~~js
app.get("/register", (req, res) => {
//==语法:res.sendFile(absolutefilepath)==
// res.sendFile("./img/a.jpg"); // path must be absolute or specify root to res.sendFile
res.sendFile(path.join(__dirname, "img/a.jpg"))
})
~~~
### 3.3 request对象
#### 3.3.1 query
- 作用:获取url地址后面的==get参数==(url?后面的查询字符串),以对象的形式返回
- ==语法:request.query==
~~~js
//4.定义请求
app.get("/login",(req,res)=>{
//req.query:获取get的请求参数,以对象的形式
//http://localhost:3000/login?username=123&password=456
console.log(req.query); //{ username: '123', password: '456' }
res.send("这个登录的响应结果");
})
~~~
#### 3.3.2 params
- 动态路由:变化的路由(路径)
~~~js
银河护卫队3 : https://movie.douban.com/subject/26258779
长空之王 (2023) : https://movie.douban.com/subject/35209731
人生路不熟 (2023):https://movie.douban.com/subject/35653205
这么多年 (2023): https://movie.douban.com/subject/35591164
灌篮高手: https://movie.douban.com/subject/35315950
~~~
电影数据庞大,操作都是一样,根据电影id的不同,返回不同的数据
~~~js
//4.定义路径
app.get("/subject/1",(req,res)=>{
res.send("银河护卫队3")
})
app.get("/subject/2",(req,res)=>{
res.send("银河护卫队3")
})
....
~~~
- 定义动态路由:“/subject/:id”
- 作用:获取动态路径参数(动态路由)
- ==语法:request.params==
~~~js
/*
定义动态路径
语法:"/subject/:参数名"
前端发请求:http://localhost:3000/subject/001
后端接收动态路径:req.params {id: '001' }
*/
app.get("/subject/:id",(req,res)=>{
//获取路径中的动态参数:req.params ,以对象的形式返回
console.log(req.params); // {id: '001' }
res.send("动态路径")
})
~~~
- 需求:根据前端发送的不同请求,返回不同的电影信息
- 例:/movie/
- 数据
~~~js
let movies = [
{id:"26258779",name:"银河护卫队3",url:"https://movie.douban.com/subject/26258779"},
{id:"35209731",name:"长空之王 (2023)",url:"https://movie.douban.com/subject/35209731"},
{id:"35653205",name:"人生路不熟 (2023)",url:"https://movie.douban.com/subject/35653205"},
{id:"35315950",name:"这么多年 (2023)",url:"https://movie.douban.com/subject/35315950"}
]
~~~
- 代码
~~~js
let movies = [
{id:"26258779",name:"银河护卫队3",url:"https://movie.douban.com/subject/26258779"},
{id:"35209731",name:"长空之王 (2023)",url:"https://movie.douban.com/subject/35209731"},
{id:"35653205",name:"人生路不熟 (2023)",url:"https://movie.douban.com/subject/35653205"},
{id:"35315950",name:"这么多年 (2023)",url:"https://movie.douban.com/subject/35315950"}
]
//4.定义请求
app.get("/movie/:id",(req,res)=>{
//5.获取动态路径参数
let idObj = req.params; //{id:"001"}
//6.查询对应id的电影信息
let isHave = movies.find(value=>{
return value.id == idObj.id
});
//7.返回id的电影信息
if(isHave){
res.send(isHave)
}else{
res.send("未找到该影片")
}
})
~~~
## 4.工具使用
### 4.1 nodemon
- 作用:通过nodemon运行代码,后端代码修改以后前端可以直接刷新执行,不需要重启服务器
- 下载安装(全局包,在任意位置运行以下命令即可)
~~~js
npm i nodemon -g
~~~
- 使用:运行后台文件时把node换成nodemon执行就可以了
~~~js
node 文件名
nodemon 文件名
~~~
![image-20230509155933654](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230509155933654.png)
### 4.2 Rest Client
- vscode插件
- 作用:接口测试工具,测试服务器定义的路径(路由)
- 安装:在vscode中搜索插件安装
- 使用
- 创建.http文件(在这个文件中进行测试)
- 写测试代码
~~~sh
#注释
#定义变量
@url = http://localhost:3000
#书写表中的请求信息 请求方法 url
#02代码中的get请求
GET http://localhost:3000/login
### 两个测试请求之间用3个#隔开
### 02代码中的post请求
POST http://localhost:3000/login
###
GET {{url}}/login
~~~
### 4.3 代码片段
- 把常用的一些代码定义成代码片段
- 操作步骤
- vscode中选择==文件==选项--==首选项==--==配置用户代码片段==--==新用户片段==--==输入片段名称==
- 把==Example:==后面的代码取消注释
![image-20230509161156184](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230509161156184.png)
- 网站:https://snippet-generator.app/?description=&tabtrigger=&snippet=&mode=vscode
## 5.路由
### 5.1. 路由概述
- 什么是路由
广义上来讲,==路由就是映射关系==。对于我们网络请求中的路由是:每一次请求对应每一个请求处理的函数。
- 现实中的路由
![3-3现实中的路由](img\3-3现实中的路由.png)
- 路由的作用
你想使用某种服务,那么一定有一个对应的路由。路由会给我们提供相应的服务(映射关系)
### 5.2 Express中的路由(Node的路由)
- 语法:app.method( path,callback )
- 参数说明:
- method:代表请求方式,比如get,post ,delete ,put
- path:代表请求路径 ,必须以 / 开头,同时可以定义动态路径 /:参数
- callback:代表回调函数,用户请求匹配到路由以后要做的事情。( request,response )
- ==注意:==
- 必须包含三个方面:==请求方法、请求的路径、处理函数== 缺一不可。
- 匹配到( 匹配成功 ):==只有方法、路径都相等才算匹配成功==
~~~js
app.get("/login")
post http://localhost:3000/login 匹配不成功,请求方式不一样
get http://localhost;3000/register 匹配不成功,请求路径不一样
get http://localhost;3000/login 匹配成功,请求方式和路径都一样
~~~
- 匹配流程
- 每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数
匹配成功: 一个请求方法,请求路径地址 ==(只有方法、路径都相等才算匹配成功 )==
- 在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则 Express 会将这次请求,转交给对应的 function 函数进行处理,主要是处理业务,并且把最终的结果响应给前端,且==一定是有结果返回==
- 如果从上到下有相同的路由,则会匹配第1个。==定义相同的路由是没有意义的==
![](C:\Users\Administrator\Desktop\three\day07_express\note\img\3-4路由匹配流程.png)
### 5.3. express.Router 模块化路由
- 模块化:把公共的代码提出来放到一个js文件中(commonjs)
不能把所有的路由都放到一个js文件中,不好管理和操作,要分门别类
- 不能把所有的路由信息放在一个js文件中,需要分门别类的抽离出来 。
- 使用步骤
- 创建一个模块化路由的文件夹 routes
- 在routes文件夹中创建模块化文件 .js
- 编辑模块化路由代码
~~~js
//1.引入express模块
const express = require("express");
//2.创建路由对象
const routerA = express.Router();
//3.定义路由(请求路径)
routerA.get(path,callback)
routerA.post(path,callback)
routerA.delete(path,callback)
routerA.put(path,callback)
//4.暴露数据--只能用module.exports暴露
module.exports = routerA
~~~
- 在需要使用的js文件中引入
~~~js
let rA = require("./或../模块化路由的路径");
app.use(rA);
~~~
- 需求:做一个学校管理系统
~~~js
学生端口:查询,添加,更新,删除
教师端口:查询,添加,更新,删除
管理员端口:查询,添加,更新,删除
课程端口:查询,添加,更新,删除
课表端口:查询,添加,更新,删除
~~~