目录
Vue项目中pinia的使用(类似于Springboot中的ThreadLocal)
笔记总结:
在我们从前端通过axios发送异步请求,就会等待服务器给我们响应结果,因为这是一个异步的,所以服务器响应的这个结果什么时候返回来我们就不得知了(它需要耗费时间)。
同步的等待服务器响应的结果:
我们可以借助于js提供的await(同步的等待服务器响应结果,如果服务器没有响应回来,这个方法就不会结束)和aysnc(把函数设置成异步函数)
例如:
const addCategory = async() =>{
//调用接口
let result = await articleCategoryAddService(categoryModel.value);
ElMessage.success(result.message? result.message:'新增成功');
//新增成功了应该刷新一下页面 , 调用获取所有文章分类的函数
articleCategoryList();
dialogVisible.value = false;
}
拦截器
背景:在我们写每次发送完请求后,都有then和catch且这些代码都是重复性代码,我们可以进行优化
封装到一个工具类request.js中
(Promise.reject(err)的作用就是:把异步的状态转换成失败的状态)
实例:
//添加响应拦截器
instance.interceptors.response.use(
result=>{
if(result.data.code === 0)
return result.data;
// alert(result.data.msg?result.data.msg:'服务异常');
ElMessage.error(result.data.msg?result.data.msg:'登陆失败');
return Promise.reject(result.data);
},
err=>{
//如果响应状态码时401,代表未登录,给出对应的提示,并跳转到登录页
if(err.response.status === 401){
ElMessage.error('请先登录');
router.push('/login');
}
else {
ElMessage.error('服务异常');
}
return Promise.reject(err);//异步的状态转化成失败的状态
}
)
export default instance;
(我们添加的拦截器本身就是异步的,所以我们在调用的js代码中不需要写await和aysnc)
跨域问题
比如我们在前端页面进行后端服务(前端的端口是5173,后端的端口是8080)
解决方法:通过配置代理的方式
只有浏览器才有跨域问题,如果我们从服务端发起,就不会有跨域问题
实现:
首先在request.js中
原来的baseURL:'http://localhost:8080'改成'/api',/api的作用是给我们访问后台的路径添加一个标识,如果我们没有配置localhost:8080什么的,它会默认把AJAX请求所在的圆给他拼上去(http://localhost:5173/api)
还需要在vite.config.js中进行配置
实例:
import path from 'node:path'
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
//配置代理
server: {
proxy: {
'/api': {
target: 'http://localhost:8080', // 后端服务器地址
changeOrigin: true, // 是否改变请求域名
rewrite: (path) => path.replace(/^\/api/, '')//将原有请求路径中的api替换为''
}
}
}
})
具体实现
当我们发起这个请求后,我们在路径中发现了api,就会把路径换成http://localhost:8080,然后在配置代理中把api替换成' '
Vue项目中pinia的使用(类似于ThreadLocal)
使用场景:携带token
使用方法:
这样我们在登录成功后就可以把token存储到pinia中,实例:
//定义数据模型
const registerData = ref({
username: '',
password: '',
rePassword: ''
})
import { ElMessage } from 'element-plus'
import {userRegisterService,userLoginService} from '../api/user.js'
//登录 绑定数据,复用注册表单的数据模型
//表单数据校验
//登录函数
//导入token状态
import { useTokenStore } from '@/stores/token.js'
import {useRouter} from 'vue-router'
const router = useRouter()
const tokenStore = useTokenStore();
const login = async() =>{
//调用接口完成登录
let result = await userLoginService(registerData.value)
//把得到的token存储到pinia中
tokenStore.setToken(result.data)
ElMessage.success(result.message?result.message:'登录成功');
//跳转到首页(借助于路由)
router.push('/')
}
使用token:
import request from '@/utils/request'
import { useTokenStore } from '../stores/token'
//文章分类列表查询
export const articleCategoryListService = () => {
//获取token状态
const tokenStore = useTokenStore()
//通过请求头Authorization携带token(已经在拦截器中做了统一处理)
//在pinia中定义的响应式数据都不需要.value
return request.get('/category', { headers: { 'Authorization': tokenStore.token } })
// return request.get('/category')
}
但是如果我们每次在发送请求的时候都手动去写headers就会比较繁琐,为了解决这个问题,我们可以把获取token写到拦截器里面(请求拦截器)
import axios from 'axios';
import { ElMessage } from 'element-plus'
//定义一个变量,记录公共的前缀
const baseURL = '/api';
//创建一个请求实例{通过传递一个js对象}
const instance = axios.create({baseURL})
//导入token状态
import { useTokenStore } from '@/stores/token.js';
import router from '../router';
//添加请求拦截器
instance.interceptors.request.use(
(config)=>{
//在发送请求之前做什么
let tokenStore = useTokenStore()
//如果token中有值,在携带
if(tokenStore.token){
config.headers.Authorization=tokenStore.token
}
return config
},
(err)=>{
//如果请求错误做什么
Promise.reject(err)
}
)
我们需要为pinia添加一个持久化插件
参数传递问题
默认的传递参数类型是json类型的
如果参数是一个queryString类型的,我们可以拼在后面
export const articleDeleteService = (id)=>{
//参数是一个queryString类型的
return request.delete('/article?id='+id);
}
如果参数是x-www-form-urlencoded类型的(借助UrlSearchParams完成参数传递)
export const userLoginService = (loginData) => {
const params = new URLSearchParams();
for(let key in loginData){
params.append(key,loginData[key]);
}
return request.post('/user/login',params);
}