一、简介

在网页上的各种表单模块中我们经常会看到验证码的身影,常见的验证码类型有:短信验证码、图形验证码等等。而最近我在工作中就用到了图形验证码,但后端接口返回的并不是一个图片地址,而是图片数据流,像下面这样:

Network查看:

在这里插入图片描述

console.log输出一下:

在这里插入图片描述

我们不能直接将图片数据流展示到页面上,所以我们需要想办法让图片验证码正常的展示在页面中。此处我列举两种办法:通过<img>标签的src去请求接口、通过原生ajax进行数据流转换。

二、具体方案

1、<img>标签的src直接请求接口

<img>标签的src属性,本来就是根据地址去请求对应图片数据的,既然接口返回的是图片验证码的数据流,所以我们可以直接通过 src 去请求该接口,然后接口返回的图形验证码就能通过<img>展现出来,点击切换验证码时,我们可以在点击事件中通过js操作<img>标签的src属性,使其重新请求接口,获取新的图片验证码:

具体代码:
<!-- 此处以vue为例,所以通过ref获取元素,修改src属性,原生js代码原理相同 -->
<img ref="vcImg" src="/api/v1/captcha" alt="验证码" @click="getVerifyCode()">

<script>
  // 重新获取表单验证码
    getVerifyCode () {
      // 直接通过src去请求验证码图片 通过Math.random()防止缓存问题
      this.$refs.vcImg.src = '/api/v123/captcha?' + Math.random()
    },
</script>
页面效果:

在这里插入图片描述

2、原生ajax进行数据流转换

关于这种方式,首先我们需要借助ajax对象的responseType属性来设置转换请求响应的数据类型,然后再通过window的URL对象的createObjectURL()方法,将响应数据转换成URL对象,然后将该对象赋值给img的src属性即可正常显示图形验证码。

具体代码:
<!-- 以Vue为例 -->
<img :src="src" alt="验证码" @click="getVerifyCode()">

<script>
  export default {
	data () {
		return {
			src: '' // 存储url对象
		}
	},
	methods: {
		 // 获取表单验证码
	    getVerifyCode () {
	      // 暂存this对象
	      const that = this
	      // 获取window的URL对像 并做好浏览器兼容性处理
	      const windowUrl = window.URL || window.webkitURL
	      // 开始ajax请求
	      const xhr = new XMLHttpRequest()
	      // 验证码请求地址
	      const url = '/api/v123/captcha'
	      xhr.open('GET', url, true)
	      // 设置响应数据的类型 blod是将响应数据转换成二进制数据的Blob对象
	      xhr.responseType = 'blob'
	      xhr.onload = function () {
	        if (this.status === 200) {
	          const blob = this.response
	          // 将响应数据转换成url对象 赋值给src变量 传递给img
	          that.src = windowUrl.createObjectURL(blob)
	        }
	      }
	      xhr.send()
	    }
	}
  }
</script>

页面效果:

在这里插入图片描述

注意:

首先在设置responseType属性时,我们需要确保服务器实际响应的数据类型与该格式兼容。如果服务器返回的数据与设置的 responseType 不兼容,则 response 的值将为null。
其次window的URL对象在不同的浏览器的调用方式可能有所不同,所以要做好兼容性处理。
最后就是在调用createObjectURL() 方法时,无论参数是否相同,每次调用都会创建一个新的url对象,虽然浏览器在document 卸载的时候,会自动释放它们,但是为了最佳的用户体验,最好还是选择合适的时机,通过URL.revokeObjectURL()方法将之前的url对象给释放掉。

MDN相关文档:

responseType
URL对象
createObjectURL()

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐