前后端交互

jwt (JSON web token)

简介

判断你是否有权限和服务器进行交互,相当于一个门禁吧,过程如下

在这里插入图片描述

知识点补充

token:服务端登录成功后进行签发
哈希:对复杂的数据进行摘要,10G 的内容,如果改了1kb ,那么它的哈希值也会改变的

实现方式

流程:我们以登录过程为例子,登录成功后签发 token,访问接口时携带 token

签发 Token

可以通过 jsonwebtoken 这个模块去签发 token参考 npm 上的模块说明,也可以参考 https://jwt.io/ 查看 token 的信息
在这里插入图片描述

签发的过程如下

1
2
3
4
5
6
7
8
const jwt = require("jsonwebtoken"); // 签发 token 的模块
let token = jwt.sign(
{
name: "some value",
}, // token 中携带的一些参数,你可以自己写,用 base64 加密的
"mytoken", // 秘钥名称,等会用来鉴权时会用到
{ expiresIn: "2h" } // 时效性,一般都是 2 个小时
);

后端签发好 token 后,发送给前端,前端需要保存好token,可以放到cookie 或者 localStorage 里(推荐放到localStorage

鉴权

当前端去访问后台接口时,需要在请求头中带上你的 token,注意要声明一下 Bearer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 前端
function checkApi() {
let xhr = new XMLHttpRequest();
// 需要把 token 放到头部带回服务端;
xhr.open("get", "/checkApi", true);
if (localStorage.getItem("token")) {
xhr.setRequestHeader(
"Authorization",
"Bearer " + localStorage.getItem("token")
// 如果后端是通过 jwt,这边就需要声明一下 Bearer!!!!
);
}
xhr.onload = function () {
// console.log(JSON.parse(xhr.responseText));
let res = JSON.parse(xhr.responseText);
console.log(res);
// 存token;
};
xhr.send();
}

携带好头信息后,后端接口可以这样校验,首先要引入 koajwt 这个模块,然后再写接口时,第二个参数写秘钥的名称koajwt({ secret: 'secretKey' }),举例子的话就是以下这样

1
2
3
4
5
6
7
8
const koajwt = require('koa-jwt')   // 鉴权

// 这边会自动鉴权
router.get('/checkApi', koajwt({ secret: 'mytoken' }), (ctx) => {
ctx.body = {
test: 'value..',
}
})```

图片展示如下:
在这里插入图片描述
同源情况下,如果没有权限的话,会报 401 的权限错误,返回 Authentication Error 的报错信息
在这里插入图片描述非同源去检验权限的话报如下的错误,这里不是很明白,为什么 token 错了会报这个错误呢?

在这里插入图片描述

成功的话就是正常的接口返回了
在这里插入图片描述
至此简单的 jwt 就结束了


请求工具

这里介绍几种方法,axios 以及 fetchaxios 比较常用

Axios

基础用法

axios 有两种常用的使用方法

第一种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
axios({
method: "post",
url: "http://localhost:4000/checkUser",
data: {
username: "张三",
password: "123",
},
headers: {},
}).then((res) => {
console.log(res);
if (res.data.token) {
localStorage.setItem("token", res.data.token);
}
});

第二种

1
2
3
4
5
6
7
axios
.post("http://localhost:4000/checkApi", data, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
})
.then((res) => console.log(res));

在这里插入图片描述

网络拦截

回到刚才的问题上!

提出问题

如果有很多接口都需要验证 token ,那么我们不能在每个接口里都要写验证的语句,那样的话代码就会冗余
有什么办法统一处理这些呢?

就是用拦截器。

Axios 中的拦截器

在每一个 axios 请求的时候都会走拦截器

1
2
3
4
5
6
axios.interceptors.request.use((config) => {
return config;
});
axios.interceptors.response.use((res) => {
return res;
});

拦截器可以有多个,比方说下面的例子,我们在关心一下拦截器的顺序:

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
/**
* 拦截器,所有的 axios 请求都会走这里
**/

// 请求拦截器
axios.interceptors.request.use((config) => {
console.log("请求拦截器1:>>", config);
if (localStorage.getItem("token")) {
// 在拦截器里去配置 token
config.headers.Authorization = "Bearer " + localStorage.getItem("token");
}
return config;
});
axios.interceptors.request.use((config) => {
console.log("请求拦截器2:>>");
return config;
});
axios.interceptors.request.use((config) => {
console.log("请求拦截器3:>>");
return config;
});
// 响应拦截器
axios.interceptors.response.use((res) => {
// console.log(config)
console.log("响应拦截器1:>>", res);
return res;
});
axios.interceptors.response.use((res) => {
// console.log(config)
console.log("响应拦截器2:>>", res);
return res;
});
axios.interceptors.response.use((res) => {
// console.log(config)
console.log("响应拦截器3:>>", res);
return res;
});

打印的顺序如下图所示:

在这里插入图片描述
根据顺序可以分析出,配置能够被冲掉

在这里插入图片描述

简版 Axios

抽离出来了:https://blog.csdn.net/u010263423/article/details/119274544


fetch

  • 原生的,基于 Promise 封装的
  • 默认是 get 请求。
  • react native 用的挺多。

简单案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fetch("/fetchtest", {
method: "post",
body: "name=张三&age=10", // 发送的内容写在body里了,相当于 axios 中的 data
headers: {
// 默认的应该是:Content-Type: text/plain;charset=UTF-8
"content-type": "application/x-www-form-urlencoded",
// 前端设置了这个,后台就会在 request.body 里收到 json 格式的数据
},
// content-type 描述的东西要和 body 对应上!
})
.then((res1) => {
console.log("res1:>>", res1); // 并不是我们想要的结果,而是 response 对象
// return res1.text()
// return res1.clone() // 对当前数据进行 深拷贝
return res1.json(); // 返还个 json,在第二个then 里能用到
})
.then((res2) => {
console.log("res2:>>", res2);
});
1
2
3
4
5
6
7
fetch("/fetchtest", {
method: "post",
body: JSON.stringify({ name: "张三" }), //这里如果有 'name=张三&age=10'
headers: {
"content-type": "application/json", // content-type 描述的东西要和 body 对应上!
},
});

也可以实例化一个 headers 对象,然后追加,最后赋值给 headers 即可。

1
2
3
let myHeader = new Headers();
myHeader.append("Content-type", "application/json");
myHeader.append("myTest", "123");

在这里插入图片描述
在这里插入图片描述

缺点

  • 不能上传文件
  • 兼容性,不如 xmlHttpRequest