当前位置: 首页 > article >正文

验证码——vue中后端返回的图片流如何显示

目录

前言

一、p调用接口获取验证码 + canvas画布渲染?

二、后端返回图片(图片流),前端显示

1.blob

2.arraybuffer

总结


前言

登录界面经常会有验证码,验证码的实现方式也有很多,我目前做过以下两种:

1.调用接口获取验证码 + canvas画布渲染

2.后端返回图片(数据流),前端显示

这两种方式都比较简单,本次项目技术栈为:vue2.6 + axsio ,接下来一起看看把~


一、p调用接口获取验证码 + canvas画布渲染?

这个比较简单,就是需要自己写一份canvas ,将后端获取过来得验证码显示出来,后续将验证码和识别码一起传递给后端,后端校验账户密码验证码是否一致。

1.编写canvas组件

这里我把他写成一个组件

<template>
  <div class="s-canvas" id="canvas">
    <canvas id="s-canvas"></canvas>
  </div>
</template>

<script>
export default {
  name: 'SIdentify',
  data() {
    return {
      w: '',
      h: '',
    }
  },
  props: {
    identifyCode: {
      type: String,
      default: '1234',
    },
    fontSizeMin: {
      type: Number,
      default: 26,
    },
    fontSizeMax: {
      type: Number,
      default: 30,
    },
    backgroundColorMin: {
      type: Number,
      default: 255,
    },
    backgroundColorMax: {
      type: Number,
      default: 255,
    },
    colorMin: {
      type: Number,
      default: 0,
    },
    colorMax: {
      type: Number,
      default: 160,
    },
    lineColorMin: {
      type: Number,
      default: 100,
    },
    lineColorMax: {
      type: Number,
      default: 255,
    },
    dotColorMin: {
      type: Number,
      default: 0,
    },
    dotColorMax: {
      type: Number,
      default: 255,
    },
    contentWidth: {
      type: Number,
      default: 121,
    },
    contentHeight: {
      type: Number,
      default: 50,
    },
  },
  methods: {
    //计算外盒子高度
    boxSize() {
      var contanier = document.getElementById('canvas')

      var canvas = document.getElementById('s-canvas')
      console.log(canvas, 'canvas')
      canvas.width = contanier.offsetWidth
      canvas.height = contanier.offsetHeight
      this.w = contanier.offsetWidth
      this.h = contanier.offsetHeight
      console.log(this.w, this.h, '获取到得canvas宽高')
    },

    // 生成一个随机数
    randomNum(min, max) {
      return Math.floor(Math.random() * (max - min) + min)
    },
    // 生成一个随机的颜色
    randomColor(min, max) {
      let r = this.randomNum(min, max)
      let g = this.randomNum(min, max)
      let b = this.randomNum(min, max)
      return 'rgb(' + r + ',' + g + ',' + b + ')'
    },
    drawPic() {
      let canvas = document.getElementById('s-canvas')
      let ctx = canvas.getContext('2d')
      ctx.textBaseline = 'bottom'
      // 绘制背景
      ctx.fillStyle = this.randomColor(
        this.backgroundColorMin,
        this.backgroundColorMax
      )
      // console.log(this.contentWidth,this.contentHeight,"图形大小")
      ctx.fillRect(0, 0, this.w, this.h)
      // 绘制文字
      for (let i = 0; i < this.identifyCode.length; i++) {
        this.drawText(ctx, this.identifyCode[i], i)
      }
      this.drawLine(ctx)
      this.drawDot(ctx)
    },
    drawText(ctx, txt, i) {
      ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
      ctx.font =
        this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
      let x = (i + 1) * (this.w / (this.identifyCode.length + 1))
      let y = this.randomNum(this.fontSizeMax, this.h - 5)
      var deg = this.randomNum(-45, 45)
      // 修改坐标原点和旋转角度
      ctx.translate(x, y)
      ctx.rotate((deg * Math.PI) / 180)
      ctx.fillText(txt, 0, 0)
      // 恢复坐标原点和旋转角度
      ctx.rotate((-deg * Math.PI) / 180)
      ctx.translate(-x, -y)
    },
    drawLine(ctx) {
      // 绘制干扰线
      for (let i = 0; i < 5; i++) {
        ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
        ctx.beginPath()
        ctx.moveTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        )
        ctx.lineTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        )
        ctx.stroke()
      }
    },
    drawDot(ctx) {
      // 绘制干扰点
      for (let i = 0; i < 80; i++) {
        ctx.fillStyle = this.randomColor(0, 255)
        ctx.beginPath()
        ctx.arc(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight),
          1,
          0,
          2 * Math.PI
        )
        ctx.fill()
      }
    },
  },
  watch: {
    identifyCode() {
      this.drawPic()
    },
  },
  created() {},
  mounted() {
    this.boxSize()
    this.drawPic()
  },
}
</script>

<style lang="stylus" scoped>
.s-canvas {
    width: 121px
    height: 50px;

}
</style>

2.使用组件

引入该组件并命名为identifyCode

import IdentifyCode from '@/components/identifyCode'      
<Identify-code  :identifyCode="identifyCode"></Identify-code>

初始化得时候获取后端返回得验证码

created(){
this.getCode()
}
//获取验证码   
async getCode() {
      try {
        await XX().then((res) => {
          this.identifyCode = res
        })
      } catch (err) {
        console.log(err)
      }
    }

二、后端返回图片(图片流),前端显示

首先我们明确两个点:

  1. 普通请求接收的时候是json格式,图片流的接收模式可选两种:blob和arraybuffer。
  2. blob和arraybuffer本质上都是二进制数据。如果使用blob我们只需要用 window.URL.createObjectURL(res)就可以得到图片链接;如果使用arraybuffer,我们需要将其转为base64的格式。

好啦,下面就开始啦~

首先我们先设置标签变量,如下:

 <div class="getCaptcha" @click="getimgCaptcha()">
                <img
                  :src="codeImg"
                  style="width:135px;height:40px;"
                  title="看不清,点击换一张"
                  loading="lazy"
                  alt="点击重新获取验证码"
                  srcset="">
</div>

1.blob

请求设置,代码如下:

export function getCaptcha () {
  return request({
    url: /getCaptcha,
    method: 'get',
    responseType: 'blob' //选择接收方式为blob

  })
}

图片处理,代码如下:

  getCaptcha (e) {
      getCaptcha().then(res => {
       this.codeImg = window.URL.createObjectURL(res) // 这里调用window的URL方法
        console.log(this.codeImg, '地址')
      })
      .catch(err => {
       console.log(err)
      })
    },

2.arraybuffer

请求设置,代码如下:

// 图片验证码
export function getCaptcha () {
  return request({
    url: /getCaptch,
    method: 'get',
    responseType: 'arraybuffer'

  })
}

图片处理,代码如下:

  getCaptcha (e) {
      getCaptcha().then(res => {
     //1. btoa表示 base64转ASCII ,对应的还有 atob 表示 ASCII转base64
     //2. Unit8Arrat() 是arraybuffer里面的一种类型
     const url = 'data:image/png;base64,' + btoa(new Uint8Array(res).reduce((data, byte) => data + String.fromCharCode(byte), ''))
        this.codeImg = url
        console.log(this.codeImg, '地址')
      })
      .catch(err => {
       console.log(err)
      })
    },

关于blod和arraybuffer的区别和具体用法,参考:前端二进制学习(三)

当然还有其它的二进制流,向上传文件或图片的时候用到的:File、FileReader、FormData,感兴趣可以自己去了解一下。


总结

以上就是今天要讲的内容,本文仅仅简单两种验证码的实现方式,当然还有其他的验证吗实现方式,感兴趣自己去看看把~


http://www.kler.cn/a/2819.html

相关文章:

  • Flink CDC(SQL Client)连接 MySQL 数据库教程
  • xrandr源码分析
  • 手动搭建 Ghost 博客
  • 020_Servlet_Mysql学生选课系统(新版)_lwplus87
  • 深入理解 React 架构从概览到核心机制
  • SDL线程
  • python例程:五子棋(控制台版)程序
  • PTP同步方式简单介绍 Master和Slave功能
  • Linux命令运行原理shell和bash
  • 二、Trino406系列 之 集群部署
  • AJAX,Axios,JSON简单了解
  • 看齐iOS砍掉祖传功能,Android 16G内存也危险了
  • HFish蜜罐的介绍和简单测试(一)
  • shell简单使用介绍
  • KafKa知识汇总
  • 大模型未来趋势
  • 【C++进阶】十一、哈希的应用---布隆过滤器(二)
  • Element table组件内容\n换行解决办法
  • 【C++】STL容器、算法的简单认识
  • 【CodeForces】Codeforces Round 859 (Div. 4) D
  • 看完这篇 教你玩转渗透测试靶机vulnhub——My File Server: 1
  • Android11以上版本使用高德定位,定位成功,卫星数一直为0
  • 【TypeScript 入门】14.泛型
  • 微软Bing GPT支持AI绘画了,输入文字就能出图
  • 值得记忆的STL常用算法,分分钟摆脱容器调用的困境,以vector为例,其余容器写法类似
  • Kotlin~Singleton单例模式