环境
Vue2、“axios”: “0.18.1”、webpack:“4.46.0”、ant-design-vue: “1.7.8”
描述
项目对安全要求比较高,所有后台返回的图片加载时都要加上token。比如资源图片,拍照打卡的图片,都需要鉴权。如果不带上token参数,图片请求返回都是401,无法正常显示图片。
博客这里仅讨论前端实现。
使用
为了方面理解,先讲怎么使用,再讲具体的代码实现
组件使用
先看看组件方式怎么使用,项目用了 v-viewer 图片预览插件,使用方式:把原先的img标签换成BCTokenImage组件
<viewer ref="viewer"><BCTokenImage style="width: 50px;height:40px;" v-for="item in result.images" :src="item.full_url" :key="item.id" />
</viewer>
非组件使用
网上有些方案是指令式的,也有些是querySeletor全局改,大家可以查一查
<img :src="fullUrl" v-token />
从代码实现上来说,逻辑大差不差的。因为需求紧急,img标签全局替换成组件是最快的方式(当然有些base64格式、静态图片会有问题,可以看我另一篇文章:Vue图片父子组件传入路径报错Error: Cannot find module ‘@/assets/map/red.png‘、动态加载require图片失败的问题)
实现
第一步,在 src/components 文件新增一个组件:BCTokenImage
位置:src\components\BCTokenImage\index.vue
<template><img :src="imageUrl" :alt="alt" @click="$emit('click')" />
</template><script>
import { axios } from '@/utils/http' // 封装过的axios,请求会自带token
import signMd5Utils from '@/utils/encryption/signMd5Utils'export default {name: "BCTokenImage",props: {src: String,alt: String},data() {return {imageUrl: "", // 可以默认给一个占位图片};},watch: {src: {handler(value) {this.loadImage(value);},immediate: true,}},methods: {loadImage(url) {const sign = signMd5Utils.getSign(url);const headers = { // "X-Access-Token": xxxxx, // 封装后axios对象自带了token头"X-Sign": sign, // 签名(看具体需要)"X-TIMESTAMP": signMd5Utils.getDateTimeToString(), // 时间戳(看具体需要)};axios({method: 'get',responseType: 'blob', // 重要:设置响应类型为bloburl,headers, // 重要:将签名和时间戳,添加在请求接口 Header}).then(response => {// 创建一个URL,浏览器可以使用它来加载图片this.imageUrl = URL.createObjectURL(new Blob([response]));}).catch(error => {console.error(`BCTokenImage error: ${url}加载失败!`, error);});}}
};
</script>
主要是看 loadImage 方法的逻辑,因为项目封装了axios对象,默认给请求加上token,所以这个方法的请求头没带上X-Access-Token。
第二步,在 main.js 全局注册组件
import Vue from 'vue'
import BCTokenImage from '@/components/BCTokenImage'Vue.component('BCTokenImage', BCTokenImage) // 全局注册
当然局部引入也是可以的,具体使用方式请看前面的 《使用》
效果
最终效果要看控制台的图片请求头,header成功带上了三个参数,图片请求返回不再是401
感兴趣也可以看看请求的响应内容,返回的是二进制数据
好啦,图片请求鉴权到此结束,谢谢观看,有问题评论区讨论