如何在Django音乐剧票务应用中集成二维码阅读器验证二维码有效性
音乐剧票务Django应用QR码验证问题排查
问题背景
开发了一个音乐剧票务Django应用,售票后生成QR码存入数据库,现在要实现一个页面读取QR码并验证其是否存在于数据库,但读取QR码后出现AJAX请求错误。
现有代码实现
HTML代码
<h1>QR code reader</h1> <video name="qr-video" id="qr-video" width="100%" height="100%" autoplay></video> <script> const video = document.getElementById('qr-video'); navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }) .then((stream) => { video.srcObject = stream; return new Promise((resolve) => { video.onloadedmetadata = () => { resolve(); }; }); }) .then(() => { video.play(); const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; setInterval(() => { context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { alert('QR code read: ' + code.data); sendQRcode(code.data); } }, 1000); }) .catch((error) => { console.error('Error trying to access camera: ', error); }); function sendQRcode(code) { alert('QR code sent') const url = 'https://ac7-1bd37c9a12e8.herokuapp.com/show/scanner/'; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ code: code}), }) .then((response) => { response.text().then((text) => { alert('Response from server:', text); }); if (!response.ok) { throw new Error('Network response was not ok'); alert('Response not ok') } return response.json(); }) .then((data) => { alert('Response from server: ' + data.message); }) .catch((error) => { alert('Error on the AJAX request:', error); }); } function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } </script>
Views.py代码
@csrf_exempt def scanner(request): if request.method == 'POST': data = json.loads(request.body.decode('utf-8')) qr_code_data = data.get('code') if qr_code_data: try: payment = UserPayment.objects.get(stripe_checkout_id=qr_code_data) message = 'Valid QR code!' except UserPayment.DoesNotExist: message = 'Invalid QR code!' else: message = 'QR code data don\'t exist.' return JsonResponse({'message': message}) else: return render(request, 'scanner.html')
models.py代码
class UserPayment(models.Model): app_user = models.ForeignKey(User, on_delete=models.CASCADE) payment_bool = models.BooleanField(default=False) stripe_checkout_id = models.CharField(max_length=500) qr_code = models.ImageField(upload_to='qr_codes', null=True, blank=True)
问题现象
手机读取QR码时,依次弹出提示:“QR code read”“QR code sent”“Error on the AJAX request”以及“Response from server: ”(无服务器响应内容)。
排查与解决步骤
1. 修复fetch响应处理的逻辑错误
当前代码中先调用response.text()解析响应,之后又尝试response.json(),但响应流只能被读取一次,这会导致response.json()失败,触发catch块。修改后的sendQRcode函数:
function sendQRcode(code) { alert('QR code sent') const url = 'https://ac7-1bd37c9a12e8.herokuapp.com/show/scanner/'; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ code: code}), }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); // 直接解析为JSON,避免重复读取响应流 }) .then((data) => { alert('Response from server: ' + data.message); }) .catch((error) => { alert('Error on the AJAX request: ' + error.message); }); }
2. 调试服务器端错误
在views.py中添加日志,查看请求是否到达服务器及是否有异常:
import logging logger = logging.getLogger(__name__) @csrf_exempt def scanner(request): if request.method == 'POST': try: data = json.loads(request.body.decode('utf-8')) qr_code_data = data.get('code') logger.info(f"Received QR code data: {qr_code_data}") if qr_code_data: try: payment = UserPayment.objects.get(stripe_checkout_id=qr_code_data) message = 'Valid QR code!' except UserPayment.DoesNotExist: message = 'Invalid QR code!' else: message = 'QR code data don\'t exist.' return JsonResponse({'message': message}) except Exception as e: logger.error(f"Error processing request: {str(e)}") return JsonResponse({'message': 'Server error'}, status=500) else: return render(request, 'scanner.html')
通过heroku logs --tail查看Heroku日志,确认请求处理情况。
3. 避免重复发送请求
当前setInterval每1秒检测一次QR码,读取到后会重复调用sendQRcode,添加标记防止重复发送:
let isProcessing = false; // 新增标记 setInterval(() => { if (isProcessing) return; // 正在处理时跳过 context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { alert('QR code read: ' + code.data); isProcessing = true; sendQRcode(code.data).finally(() => { isProcessing = false; // 请求完成后重置标记 }); } }, 1000);
同时修改sendQRcode函数返回Promise:
function sendQRcode(code) { alert('QR code sent') const url = 'https://ac7-1bd37c9a12e8.herokuapp.com/show/scanner/'; return fetch(url, { // 返回fetch的Promise method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ code: code}), }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { alert('Response from server: ' + data.message); return data; }) .catch((error) => { alert('Error on the AJAX request: ' + error.message); throw error; }); }
内容的提问来源于stack exchange,提问作者Matheus Marques
相关产品推荐
相关产品推荐

