You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 05:08:10