SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(三):引入 js-cookie、axios、mock 封装请求处理以及返回结果
前提:
(1) 相关博文地址:
SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(一):搭建基本环境:https://www.cnblogs.com/l-y-h/p/12930895.html SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(二):引入 element-ui 定义基本页面显示:https://www.cnblogs.com/l-y-h/p/12935300.html
(2)代码地址:
https://github.com/lyh-man/admin-vue-template.git
一、引入 js-cookie
1、简介
为了保存 token 值,可以使用 cookie 或者 localStorage 或者 sessionStorage 保存。
此处采用 cookie 进行保存,所以引入 js-cookie 插件,用于操作 cookie。
2、token
(1)简单理解一下 token 是什么?
直译为 “令牌”,是由服务端生成的一串字符串,作为客户端进行请求的一个标识。
(2)token 一般用在什么时候?
一般用于用户第一次登录系统时,服务端生成一个 token,返回给客户端,客户端下次请求时带上这个 token 发送请求,不用再带上用户名和密码,简化了验证操作。
(3)为什么使用 token?
HTTP 协议是一种无状态的协议,客户端发送请求时,服务端并不知道是哪个客户端在访问。可以使用 用户名以及密码 唯一确定用户身份,但是每次响应请求时都要验证一下用户,这就很烦。
可以使用 session 以及 sessionId 的方式去解决,当客户登录系统时,服务端验证并生成一个记录保存在 session 中,并将这条记录的 id(即 sessionID) 返回给 客户端,客户端使用 cookie 或者 localStorage 保存,再次发送请求时,带上这个 sessionID,服务端响应并找到对应的记录进行验证。
可以使用 token 的方式解决,当客户登录系统时,服务端验证并返回一个 token 给客户端,客户端下次发送请求时,带上这个 token,服务端验证 token 即可。
(4)session 与 token 区别?
session 存储是需要空间的(存储用户信息),服务器需要单独保存一份,以空间换时间。
token 可以不用存储用户信息,服务器不用保存(解密 token 即可),以时间换空间。
3、安装、引入 js-cookie
(1)npm 安装 js-cookie
【使用 npm 安装:】
npm install js-cookie
(2)引入 js-cookie
此处直接定义 一个 auth.js 并引入,使用时引入 该 js 文件即可。
也可使用 main.js 全局引用。
【在项目中引入 js-cookie:】 // 引入 token,此处直接引入,也可以在 main.js 中全局引入 import Cookies from 'js-cookie' // 设置 token 存储的 key const TokenKey = 'Admin-Token' // 获取 token export function getToken() { return Cookies.get(TokenKey) } // 设置 token export function setToken(token) { return Cookies.set(TokenKey, token) } // 移除 token export function removeToken() { return Cookies.remove(TokenKey) }
二、引入、封装 axios
1、简介
想要发送 ajax 请求,vue 项目中一般使用 axios,使用起来虽然简单,但如果不进行统一封装,随着项目越来越大,冗余代码会急剧增加,所有需要对 axios 进行二次封装,使各个组件间能够复用 axios,简化代码。
【vue 引入 axios 并简单使用 参考地址:】 https://www.cnblogs.com/l-y-h/p/11656129.html
2、封装要求
统一 url 配置(可以与代理结合起来使用解决跨域问题)。
定义请求拦截器(request),比如:设置消息头、设置 token 等。
定义响应拦截器(response),比如:统一错误处理、页面重定向 等。
3、引入 axios
(1)npm 安装 axios
【npm 安装】
npm install axios
(2)引入 axios
此处直接定义 一个 httpRequest.js 引入,使用时引入 该 js 文件即可。
也可使用 main.js 全局引用。
import Vue from 'vue' import { getToken, removeToken } from '@/http/auth.js' import router from '@/router' import { Message } from 'element-ui' import axios from 'axios' // 创建 axios 实例 const http = axios.create({ // 统一 url 配置,定义访问前缀 baseURL baseURL: '/api', // 定义请求超时时间 timeout: 10000, // 请求带上 cookie withCredentials: true, // 定义消息头 headers: { 'Content-Type': 'application/json; charset=utf-8' } }) // 定义请求拦截器 http.interceptors.request.use( config => { // 让每个请求携带 token config.headers['Admin-Token'] = getToken() return config }, error => { Promise.reject(error) } ) // 定义响应拦截器 http.interceptors.response.use( response => { const res = response.data // 当 token 失效时,清除 cookie 保存的 token 值,并跳转到登陆界面 if (res && res.code === 401) { removeToken() Message({ message: res.message, type: 'error', duration: 5000 }) router.push({ name: 'Login' }) } // 未找到页面时,跳转到 404 页面 if (res && res.code === 404) { router.push({ name: '404' }) } return response }, error => { return Promise.reject(error) } ) export default http
(3)全局挂载 axios
在 main.js 中引入 httpRequest.js 文件,并全局挂载。
import http from '@/http/httpRequest.js' // 全局挂载 http(axios),使用的时候直接使用 this.$http 即可。 Vue.prototype.$http=http
(4)简单写个案例测试一下:(仅供参考)
后端:
定义一个 AuthController,用于返回 token。
其中:
@CrossOrigin 用来解决跨域(一般加上这个即可跨域)。如果此注解不生效,可以在前端配置代理来实现跨域。
package com.lyh.template.back.controller; import com.lyh.template.back.util.Result; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/auth") @CrossOrigin public class AuthController { @RequestMapping("/token") public Result getToken() { return Result.ok().data("token", "admin"); } }
如下,接口访问正常(当然,使用 swagger 测试也一样)。
前端:
修改代理,用于跨域。
在 vue.config.js 文件中进行配置,当路径中出现 /api 时,会将其替换成 target 中的路径。
而 target 路径是从 配置文件中读取的,生产环境与开发环境的 VUE_APP_URL 不同。
注:
开发环境时:
VUE_APP_URL=http://localhost:8000
生产环境时:
VUE_APP_URL=http://localhost:9000
module.exports = { lintOnSave: false, devServer: { port: process.env.NODE_ENV == "production" ? 8000 : 9000, proxy: { '/api': { target: process.env.VUE_APP_URL, // 允许跨域 changeOrigin: true, ws: true, pathRewrite: { '^/api': '' } } } } }
修改一下 Login 组件中的登陆方法,测试一下。
发送 /auth/token 请求时,会代理到 http://localhost:8000/auth/token。
登录成功后,会打印返回数据,并跳转到主界面。
methods: { // 提交表单 dataFormSubmit() { // TODO:登录代码逻辑待完善 // alert("登录代码逻辑未完善") this.$http({ url: '/auth/token', method: 'get' }).then(response => { console.log(response) this.$router.replace({name: 'Home'}) }) } }
三、引入、封装 mock
1、简介
项目开发的时候,有时候后端接口不给力,要是必须从后端获取数据,没有其他方式获取数据,那就很蛋疼了(只能等后端接口正常,才可以继续开发前端)。
mock 是一个数据模拟生成器,用于帮助前端独立于后端进行开发,其模拟 ajax 并返回相应的数据,从而使前端不必依赖于后端接口,方便开发。
【vue关于mock的简单使用 参考地址:】 https://www.cnblogs.com/l-y-h/p/11691110.html
2、封装要求
定义不同的模块,用于响应不同组件的请求。
可以方便、快捷的关闭某个模块、或者某个请求的处理(关闭请求处理后,可以直接访问后端接口)。
3、引入 mock
(1)npm 安装 mock
【npm 安装 mock:】
npm install mockjs
(2)引入 mock
定义一个 mock 文件夹以及统一处理入口 mock.js。
定义一个 fnCreate 方法 用来处理 mock。
其中:
第一个参数为 模块名,需要通过 import 引入。
第二个参数为 是否开启 mock ,true 为开启,false 为关闭。
import Mock from 'mockjs' import * as login from './modules/login.js' // 可以通过 isOpen 参数设置是否拦截整个模块的 mock 功能 fnCreate(login, true) /** * 创建mock模拟数据 * @param {*} mod 模块 * @param {*} isOpen 是否开启? */ function fnCreate(mod, isOpen = true) { if (isOpen) { for (var key in mod) { ((res) => { if (res.isOpen !== false) { Mock.mock(new RegExp(res.url), res.type, (opts) => { opts['data'] = opts.body ? JSON.parse(opts.body) : null delete opts.body console.log('\n') console.log('%cmock拦截, 请求: ', 'color:blue', opts) console.log('%cmock拦截, 响应: ', 'color:blue', res.data) return res.data }) } })(mod[key]() || {}) } } }
(3)定义功能子模块
给不同的组件定义不同的模块,用于区分不同的操作。
比如创建一个 login.js 用来处理 登录、登出操作。
import Mock from 'mockjs' // 登录 export function getToken() { return { // isOpen: false, url: 'api/auth/token', type: 'get', data: { 'msg': 'success', 'code': 0, 'expire': Mock.Random.natural(60 * 60 * 1, 60 * 60 * 12), 'token': Mock.Random.string('abcdefghijklmnopqrstuvwxyz0123456789', 32) } } }
(4)全局引入 mock 文件
在 main.js 中引入,可以控制引入时机,比如只在开发环境下生效。
// 非生产环境, 适配mockjs模拟数据 if (process.env.NODE_ENV !== 'production') { require('@/mock') }
(5)简单测试一下。
开发环境运行时,登录会触发 mock ,在控制台打印数据。
(6)与后台接口的区别。
使用 mock 返回数据 与 访问后台接口还是有区别的。
开发环境下,若想访问后台,
方式一:可以在 main.js 中将 引入 mock 文件的代码注释掉,就可以访问了。
方式二:在 mock 的 fnCreate 方法中,将 isOpen 参数置为 false 即可(关闭 mock 功能)。
生产环境下,执行 dist 项目,可以通过 nginx 反向代理到后台服务器,进行访问(后续项目部署时再补充)。