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

验证码通过“Canvas 绘制”与“Base64 图片”渲染两种不同的实现方式显示

文章目录

  • 🎉验证码通过“Canvas 绘制”与“Base64 图片”渲染两种不同的实现方式显示
    • 一、Canvas 绘制:接口回调“字符串”通过绘制的方式显示到前端✨
      • 1、前端代码(Canvas 绘制):包含验证码区域、绘制验证码方法🎊
      • 2、效果🎊
    • 二、Base64 图片渲染:接口回调直接显示服务器返回的 “Base64 图片”显示到前端✨
      • 1、前端代码(Canvas 绘制):包含验证码区域、绘制验证码方法🎊
      • 2、效果🎊
    • 三、总结🪄
      • 1、修改方案对比
      • 2、注意事项
        • 1. Base64 格式处理
        • 2. 图片适配样式
        • 3. 缓存问题
        • 4. 安全性增强
      • 3、 后端接口建议
      • 4、 性能优化

🎉验证码通过“Canvas 绘制”与“Base64 图片”渲染两种不同的实现方式显示

一、Canvas 绘制:接口回调“字符串”通过绘制的方式显示到前端✨

1、前端代码(Canvas 绘制):包含验证码区域、绘制验证码方法🎊

<view @tap="refreshCaptcha" class="captcha-container">
  <canvas type="2d" id="captchaCanvas"></canvas>
</view>
/**获取账号密码登录的图片验证码*/
			refreshCaptcha() {
				const that = this;
				uni.request({
					url: that.$helper.HHH,
					method: 'POST',
					data: {},
					success: res => {
						if (res.data.result) {
							that.originalValidCode = res.data.data2; // 保存验证码文本
							that.drawCaptcha(res.data.data); // 绘制验证码
						} else {
							uni.showToast({
								title: '获取验证码失败',
								icon: 'none'
							});
						}
					},
					fail: () => {
						uni.showToast({
							title: '获取验证码失败',
							icon: 'none'
						});
					}
				});
			},
			/**绘制验证码,直接使用即可*/
			async drawCaptcha(text) {
				try {
					// 获取 canvas 实例
					const query = uni.createSelectorQuery().in(this);
					const canvas = await new Promise(resolve => {
						query.select('#captchaCanvas')
							.fields({
								node: true,
								size: true
							})
							.exec((res) => {
								resolve(res[0].node);
							});
					});

					const ctx = canvas.getContext('2d');

					// 设置 canvas 大小
					const dpr = uni.getSystemInfoSync().pixelRatio;
					canvas.width = 100 * dpr;
					canvas.height = 32 * dpr;
					ctx.scale(dpr, dpr);

					// 清空画布
					ctx.clearRect(0, 0, 100, 32);

					// 设置背景色
					ctx.fillStyle = '#f0f0f0';
					ctx.fillRect(0, 0, 100, 32);

					// 绘制文字
					ctx.fillStyle = '#333333';
					ctx.font = 'bold 20px Arial';
					ctx.textBaseline = 'middle';

					// 计算文字总宽度以居中显示
					const textWidth = ctx.measureText(text).width;
					const startX = (100 - textWidth) / 2;

					// 随机倾斜每个字符
					for (let i = 0; i < text.length; i++) {
						const x = startX + i * (textWidth / text.length);
						const y = 16; // 垂直居中

						ctx.save();
						// 随机旋转角度
						const angle = (Math.random() - 0.5) * 0.3;
						ctx.translate(x, y);
						ctx.rotate(angle);
						ctx.fillText(text[i], 0, 0);
						ctx.restore();
					}

					// 添加干扰线
					for (let i = 0; i < 3; i++) {
						ctx.beginPath();
						ctx.strokeStyle = `rgb(${Math.random()*150},${Math.random()*150},${Math.random()*150})`;
						ctx.moveTo(Math.random() * 100, Math.random() * 32);
						ctx.lineTo(Math.random() * 100, Math.random() * 32);
						ctx.stroke();
					}

					// 添加干扰点
					for (let i = 0; i < 30; i++) {
						ctx.fillStyle = `rgb(${Math.random()*150},${Math.random()*150},${Math.random()*150})`;
						ctx.beginPath();
						ctx.arc(Math.random() * 100, Math.random() * 32, 1, 0, 2 * Math.PI);
						ctx.fill();
					}
				} catch (e) {
					console.error('绘制验证码失败:', e);
				}
			},

2、效果🎊

示例图片

二、Base64 图片渲染:接口回调直接显示服务器返回的 “Base64 图片”显示到前端✨

1、前端代码(Canvas 绘制):包含验证码区域、绘制验证码方法🎊

  • 确保后端返回的 Base64 数据 不带前缀(如 data:image/png;base64,),前端需要手动拼接:
    this.captchaImage = `data:image/png;base64,${res.data.base64}`;
    
<view @tap="refreshCaptcha" class="captcha-container">
  <canvas type="2d" id="captchaCanvas"></canvas>
</view>
// 1. 定义数据
data() {
  return {
    captchaImage: '' // 存储 Base64 图片数据
  }
},

// 2. 获取验证码(从后端接口)
methods: {
  async refreshCaptcha() {
    try {
      const res = await api.getCaptcha(); // 替换为你的接口
      this.captchaImage = `data:image/png;base64,${res.data.base64}`;
    } catch (error) {
      console.error('获取验证码失败:', error);
    }
  }
},

// 3. 初始化时加载
onLoad() {
  this.refreshCaptcha();
}

2、效果🎊

示例图片

三、总结🪄

通过用 Base64 图片渲染验证码,你实现了以下优化:

  1. 降低前端复杂度:无需维护 Canvas 绘制逻辑。
  2. 提升安全性:验证码由后端生成,避免前端模拟。
  3. 更好兼容性:Base64 图片在所有平台表现一致。

1、修改方案对比

特性Canvas 绘制Base64 图片渲染
实现方式动态生成图形/文字直接显示服务器返回的 Base64 图片
性能依赖前端计算直接渲染,性能更优
维护性需维护绘制逻辑仅替换图片源即可
安全性前端生成,可能被破解后端生成,更安全

2、注意事项

1. Base64 格式处理
  • 确保后端返回的 Base64 数据 不带前缀(如 data:image/png;base64,),前端需要手动拼接:
    this.captchaImage = `data:image/png;base64,${res.data.base64}`;
    
2. 图片适配样式
  • 添加 CSS 确保图片显示正常:
    .captcha-container image {
      width: 100%;  /* 宽度自适应容器 */
      height: auto; /* 高度按比例缩放 */
    }
    
3. 缓存问题
  • 如果验证码图片不变,浏览器可能缓存旧图。解决方法:
    • 在 URL 后加随机参数(如 ?t=${Date.now()}
    • 或要求后端在 HTTP 头中设置 Cache-Control: no-cache
4. 安全性增强
  • 建议后端对验证码 Base64 数据加密,前端解密后使用(防止中间人攻击)。

3、 后端接口建议

确保后端返回的数据结构包含原始 Base64 数据:

{
  "code": 200,
  "data": {
    "base64": "iVBORw0KGgoAAAANSUhEUgAAAMgAA..." // 纯 Base64 字符串
  }
}

4、 性能优化

  • 压缩图片:后端应返回压缩后的 Base64 数据(减少传输体积)。
  • 懒加载:验证码图片仅在需要时请求(如点击刷新时)。

相关文章:

  • 城电科技|零碳园区光伏太阳花绽放零碳绿色未来
  • 《论语别裁》第02章 为政(08) 诗的伟大
  • GenBI 中如何引入 LLM 做意图路由,区分查数据还是闲聊
  • 【ManiSkill】环境success条件和reward函数学习笔记
  • 解决HuggingFaceEmbeddings模型加载报错:缺少sentence-transformers依赖包
  • 作业(6)
  • WebGL图形编程实战【3】:矩阵操控 × 从二维到三维的跨越
  • 将网页操作的脚本自动保存成yaml ,然后修改使用
  • vueRouter的hash模式跟history的区别
  • pip show protobuf ValueError: invalid literal for int() with base 10: ‘‘
  • 小迪安全109-php模型动态调试,反序列化,变量覆盖,tp框架,原生pop链
  • 第30周Java分布式入门 分布式基础
  • C++20:make_shared_for_overwrite与make_unique_for_overwrite
  • 关于deepseek
  • 自动化构建攻略:Jenkins + Gitee 实现 Spring Boot 项目自动化构建
  • 免费OpenAI gpt-4o-mini-tts API调用(已开源)
  • 如何快速解决django存储session变量时出现的django.db.utils.DatabaseError错误
  • 在Windows下VSCodeSSH远程登录到Ubuntu
  • MySQL多表查询核心指南
  • Unity程序嵌入Qt后点击UI按钮Button没有反应
  • 上海营销平台网站建设/google下载官方版
  • 金山做网站的公司/360社区app
  • 无锡网站制作公司排名/邹平县seo网页优化外包
  • 网站布局图片/怎么制作一个网站5个网页
  • php租车网站源码/百度热搜广告位
  • 自建外贸推广网站有哪些/seo搜索优化是什么