如何通过接口实现动态二维码的定时刷新

如何通过接口实现动态二维码的定时刷新?

感觉本篇对你有帮助可以关注一下我的微信公众号(深入浅出谈java),会不定期更新知识和面试资料、技巧!!!

如何通过接口实现动态二维码的定时刷新

一、需求场景

在Web应用中,动态二维码常用于以下场景:

  1. 登录验证:微信扫码登录、APP扫码授权
  2. 支付场景:支付宝/微信支付码定时刷新
  3. 票务系统:电子票二维码防截屏盗用
  4. 会员系统:动态会员码累计积分

二、技术方案设计

1、 整体流程

如何通过接口实现动态二维码的定时刷新

三、前端部分

大致流程

1、请求后端接口(按照现有项目格式即可)

2、后端接口的返回类型定义(byte[])

3、前端接收时定义响应类型(重点:responseType: 'arraybuffer'

4、对后端返回数据进行转化:arrayBufferToBase64

5、对数据和标签进行绑定

具体实现

1、获取后端 二维码 图片接口

	import { 		generateMemberCode 	} from '@/api/inter/member-code.js';  data() { 			return { 				codeImg: '', 				timer: null, // 添加定时器引用, 			} 		}, 		onShow() { 			// 立即加载一次 			this.makeMemberCode();  			// 设置定时器(注意保存引用) 			this.timer = setInterval(() => { 				this.makeMemberCode(); 			}, 30000); 		}, 		onHide() { 			// 页面隐藏时清除定时器 			if (this.timer) { 				clearInterval(this.timer); 				this.timer = null; 			} 		},         methods: { 			async makeMemberCode() { 				const memberId = 1; // 使用假数据中的 id 				const memberName = '张三'; // 使用假数据中的 nickname 				const params = { 					memberId, 					memberName 				}; 				try {                     // 调用后端接口(这里可改成符合你项目的请求方式) 					const response = await generateMemberCode(params); 					console.log('完整响应:', response);  					// 调试数据类型 					console.log('响应数据类型:', typeof response);  					// 处理二进制数据(适用于小程序) 					if (typeof response === 'object' && response instanceof ArrayBuffer) { 						const base64 = uni.arrayBufferToBase64(response); 						this.codeImg = `data:image/png;base64,${base64}`; 						console.log('新的 codeImg:', this.codeImg); // 调试输出 					} else if (typeof response.data === 'string') { 						this.codeImg = `data:image/png;base64,${response.data}`; 					} 					// 处理URL 					else if (response.data.imageUrl) { 						this.codeImg = response.data.imageUrl; 					} 				} catch (error) { 					console.error('请求失败:', error); 					uni.showToast({ 						title: '会员码加载失败', 						icon: 'none' 					}); 				} 			}         } 

上面部分用到的代码: member-code.js

import { HttpClient } from '@/api/utils/request.js'; // 确保路径正确 import api from '../../config/api.js'; // 导入 API 配置  const http = new HttpClient(api.base);   /**  * 获取后端二维码  */ export async function generateMemberCode(params) {     try {         const response = await http.getbuffer('/api/wx/generate-qrcode',params);         console.log('Response:', response);         return response; // 返回响应数据     } catch (error) {         console.error('Error:', error);         throw error; // 继续抛出错误以供上层处理     } } 

请求接口工具类:request.js

class HttpClient { 	constructor(baseURL) { 		this.baseURL = baseURL; 	}  async getbuffer(url, params = {}) { 		try { 			//await this.checkTokenAndNavigate(); // 在发送请求前检查 token 			const queryString = this.buildQueryString(params); 			const fullURL = `${this.baseURL}${url}${queryString}`; 	 			return new Promise((resolve, reject) => { 				uni.request({ 					url: fullURL, 					method: 'GET', 					header: { 						'Content-Type': 'application/json', 						'X-Auth-Token': `${uni.getStorageSync('token')}` // 如果需要在 header 中发送 token 					}, 					responseType: 'arraybuffer', // 指定响应类型为 arraybuffer 					success: (response) => { 						resolve(response.data); 					}, 					fail: (error) => { 						console.error('GET request error:', error); 						reject(error); 					} 				}); 			}); 		} catch (error) { 			// 如果 checkTokenAndNavigate 抛出错误(例如没有 token),则这里处理错误 			return Promise.reject(error); 		} 	}     buildQueryString(params) { 	  if (!params || Object.keys(params).length === 0) { 	    return ''; 	  } 	  return '?' + Object.keys(params) 	    .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key])) 	    .join('&'); 	} }  export { 	HttpClient }; 

接口地址Api 配置类:API.js

// 生产环境 const prod = {   base: "http://XXXXXX:8099", };  // 开发环境 const dev = {   base: "http://XXXXXXX:8099", };  // 默认生产环境 let api = prod;  // 如果是开发环境 if (process.env.NODE_ENV === "development") {   api = dev; }  // 微信小程序和App的打包方式建议为生产环境,所以这块直接条件编译赋值() // #ifdef MP-WEIXIN || APP-PLUS // 这个直接使用的是 dev 地址 api = dev; // #endif  export default {   ...api, }; 

2、模板进行渲染

	<view class="qrcode d-flex just-content-center align-items-center"> 					<image :src="`${codeImg}`" style="width: 350rpx; height: 350rpx;"></image> 				</view> 

四、后端部分

具体实现

1、添加依赖

<!-- ZXing Core and Java SE -->     <dependency>         <groupId>com.google.zxing</groupId>         <artifactId>core</artifactId>         <version>3.4.1</version>     </dependency>     <dependency>         <groupId>com.google.zxing</groupId>         <artifactId>javase</artifactId>         <version>3.4.1</version>     </dependency> 

2、接口实现controller

import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter;  import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;  import java.io.ByteArrayOutputStream; import java.nio.file.FileSystems; import java.util.HashMap; import java.util.Map;  @RestController public class QRCodeController {      @GetMapping("/generate-qrcode")     public ResponseEntity<byte[]> generateQRCode(             @RequestParam String memberId,             @RequestParam String memberName) throws WriterException {                  // 构建二维码内容(内容可根据自己业务动态修改)         // 建议加上唯一标识,安全码、起始时间、状态等,保证二维码安全性         String qrContent = "Member ID: " + memberId + ", Member Name: " + memberName;          // 设置二维码参数         int width = 300;         int height = 300;         String imageFormat = "PNG"; // 图片格式          Map<EncodeHintType, Object> hints = new HashMap<>();         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");          // 生成二维码         QRCodeWriter qrCodeWriter = new QRCodeWriter();         BitMatrix bitMatrix = qrCodeWriter.encode(qrContent, BarcodeFormat.QR_CODE, width, height, hints);          // 将二维码写入字节数组输出流         ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();         MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, pngOutputStream);          // 返回二维码图片         HttpHeaders headers = new HttpHeaders();         headers.setContentType(MediaType.IMAGE_PNG);         return new ResponseEntity<>(pngOutputStream.toByteArray(), headers, HttpStatus.OK);     } }  

接口测试

GET http://localhost:8080/generate-qrcode?memberId=12345&memberName=JohnDoe

如何通过接口实现动态二维码的定时刷新

前端处理后端的数据时,在一定要指定相应类型:responseType: 'arraybuffer'

如何通过接口实现动态二维码的定时刷新

五、效果展示

如何通过接口实现动态二维码的定时刷新

六、安全性设计

风险 防御方案
二维码盗用 30秒短时效性 + 单次有效性验证
接口暴力请求 限流策略(如Guava RateLimiter)
中间人攻击 全站HTTPS + 数据签名
XSS攻击 前端输入过滤 + CSP安全策略

七、总结

关键技术栈

  • 前端定时器 + 二进制流处理
  • 后端二维码生成 + 状态管理
  • 高效的缓存策略

最佳实践建议

  1. 始终为二维码添加时效性和唯一性标识
  2. 敏感操作需二次确认(如扫码后的授权确认)
  3. 监控二维码使用率,优化生成策略

通过前后端协作,动态二维码既能提升用户体验,又能有效保障系统安全性。

最后文章有啥不对,欢迎大佬在评论区指点!!!
如果感觉对你有帮助就点赞推荐或者关注一下吧!!!
如何通过接口实现动态二维码的定时刷新

发表评论

评论已关闭。

相关文章