在Django后端生成二维码并发送给ReactJS前端,无需在服务器上保存二维码

问题描述 投票:0回答:1

我正在开发一个项目,其中有一个 Web 应用程序frontend = React JSbackend = Django (python)。 现在我的任务是生成 QR 码,其中包含 JSON 以及有关产品的信息。

我使用了python中的“qrcode”库,适当修改了数据,并使用库的函数将其保存在QR码中。 当我尝试将 QR 保存到服务器并加载它时,一切正常。

现在我需要将二维码传输到前端。 我想尝试一下,而不在服务器上保存QR图像,只传输然后在前端渲染的数据。 这是我尝试过的代码

BACKEND

class generateQR(APIView):
    permission_classes = (IsAuthenticated, )
    
    def get(self, request, software_id):
        user = request.user
        try:
            software = Software.objects.get(id=software_id)
            
            location= software.location.all()
            namelocation=[l.namefor l in location] # get location.nameatribut from object location

            qr_data={
                "kcm":software.kcm,
                "name":software.name,
                "admin":software.admin.name,
                "location":name,
            }
            #print("QR data:",qr_data)
            
            qr=qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_L,
                box_size=10,
                border=4,
            )
            qr.add_data(qr_data)
            qr.make(fit=True)
            img=qr.make_image(fill_color="black", back_color="white")
            img_data=BytesIO()
            img_data.seek(0)

            #img.save("testQR.png") # save localy to server, I want to avoid it

            img.save(img_data) # save to "img_data" the created "img" if I tried "img.save(img_data, format="PNG")" - it failed here  
            img_data.seek(0) # set BytesIO pointer to the begining
            img_binary=img_data.getvalue()
       
            print("img binray: ",str(img_binary))
            return Response({"qr": str(img_binary) }, status=status.HTTP_200_OK)
        except : 
             ..........code continues ............

我在前端有这部分:

{/* .... some code above ....*/}

const generateQRCode=async()=>{
      //Call backend endpoint for generate QR code
      console.log("sending with id:",id);
      try{
        const response = await axios.get(API_SOFTWARE+id+"/genQR"); //,{ responseType: 'arraybuffer' }
        console.log("resp: ",response.data);
        //const dataconverted = new Uint8Array(response.data);
        //console.log("converted data: ", dataconverted);
        const blob = new Blob([response.data.qr]); //transfer binary to blob , { type: 'image/png' }
        console.log("blob: ",blob);
        const url = URL.createObjectURL(blob); //create url for show QR
        console.log("url: ",url);
        setQRCode(url);

      }catch (err){
        console.log("Error in generating QR code", err);
      }
    };

{/* ..... code continues ....*/}

{/* Show QR code if it exists */}
{/* ..... in return some code above ....*/}
          {QRCode && <img src={QRCode} alt="QR" />}
          <Button variant="secondary" onClick={generateQRCode}>
            Generate QR
          </Button>
{/* ..... code continues ....*/}

当我尝试调试问题所在时,我发现我得到的数据与响应中后端生成的数据相同。

这些数据是:

b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\xea\x00\x00\x01\xea\x01\x00\x00\x00\x00\xe3\x160\x97\x00\x00\x03\x18IDATx\x9c\xed\xdaIn\xc4 \x10@Q$\x1f\xc0G\xea\xab\xfbH>\x80\xa5JCMx\x88\x94\x86^d\xf1Y$\x1exxS\x02\xaa\xe8"3m+p8\x1c\x0e\x87\xc3\xe1\xf0\xff\xc4\x8b\xb5E\xf2V\xb6\xf5x\xbf\xdd\xebU\xbd\x7f\xd5\xabz\xab\xed\x05\x87O\xf2v#\xfb"\xfe\xb8\xa1z\xbb\xdb@\xef\xabv\xeb_\x80\xc3\xa7\xf9^\xbc\x83\xbc\xbb\x96\xb5F\xee\xda\xdeE\xe4j\x0c/\xd2\x82\x1b\x0e\xff\x1e\x7f\xf7j\x8f-@}\xfa<b\xaa\x84\xc3\xbf\xce\xdf\xa1z\xc4@\x87\xce\x97\xddh/8\xfc{\xbc\xfdK.\xf6\xc7\x17\xedz%>n\n8|\x82G2\xd2\xc5\xe6\xf3\x9f\xc7d\x04\x0e\xff\x9cg\xb3\xf0\xd5\xbd\xa1m\x10=\xf1]\xe4\xda\xe0\xf0q\xde\xbaj\xce\x11]-,3-\x89\xa0\xd5\r"\x1c>\xc7m\xe3\xd7.\x1b_Ero\x98\xa3i\xe4n\xb7\xa9\x12\x0e\xff\x9ck\x87\x12\x89\x87\xf5?\xb4\x97\xff9J\xff\x198|\x8e\xb7yPk.\x12\xa1j\x19\xb1\xf8m|\xe6>U\xc2\xe1\xa3\\\xbc\x7f\xae\xc3\xfd,\xb9\x06\x97K\n\x0c\x87\x0f\xf0\x8cC\x9d k\x13\xd1\xb9\xd1\xd7\xeb\xb6s\xdc<\x86\xf5\xa3p\xf8\x04/YP^s\x8c\xa5C\xfd\xa6\xb1\xb6\x17\x1c>\xc7\xed\x18\xc3\x831\xa5_I\xa4 G\x047\x1c>\xc5m\xaa\xdc\xb3\xc3\xe5,\xad\xd8mL\x9f\xf6U8|\x98\xdb\xe3K\xe2\x11\xcb\xf2y\xbf\xe8\xe1\x0b\x87\xcf\xf1\xcd\x17h{\xbc&\xcf\x99\xb3\xff\x0c\x1c>\xcb\xef\xe8\xe8\xc6\xb5\x12L\xb1,\xf9)\x97\x81\xc3\x07\xb8\x16^|\n\xcc\xea\x9fN\x8b]}\xaf\x14\xab\xd2\xc0\xe1s<\x9f\xe8\xb60r\x93\x8c\xe6\x13\xbf\xad\xefp\xf8\x00\x97\xb6\x0e\xd7\xb6\xdahY\x8c)VZ\xceqs48|\x94[\xa6\xe1E>[\x82#\xf1\xed\xf6\x8b:s\xe6-\x1c>\xcc\xb5\xdc\x12\x99\xee%\x05\x891\xc4\xaa/\xd7\xa0\x85\xc3?\xe7\xa7J\x9f\xef\x12\xbb\x9asd\xbfY\x07\x84\xc3g\xb9\xae\xb9\xf1\x93\x81\x97\xbe\xcbe\xb9\xbd]t\x0c\x9fW\xe1\xf0)n\xc5\xe3\xd5\xc2\xb2\xb5\xb6\x18[\x1e\x9c\xc5\xc0\xbd<\x96\xfb\xe0\xf0\x01.Q}\x119\x97\xf6|\xaal\x19q\\Y\xac\xc3\xe1\xc3\\gI[\x87E\xb3_\x8b\\\x8fW\x1f\xf7)h\xe1\xf0\x01n\xfb@\xef\xaf\xc9\xb0v\x88\xa0\xd5\x05Z\x0f9J\x81\xc3g\xb9\x15Y"hM\x1e\xbaJ\xe7\xf2\xdd\r\t\x87OrKA\xda\xb9\x99\x87\xaf\xe7\xc1mp\xdb\x11Z\xbc^\x8f6\xe0\xf0\x01\x9e\xad\xe81\x86\x97\x91O\x85?\xff\x05U7\x91\xc2\xe1\xc3\xdc\xc3q\xf1<D\xa4\xeb\xdf\xad\xcdy\xaa!p\xf8$\xefz\xf9\x95\xa7\xbb\x0f\x81\\n3-\x1c>\xc0u\x81\x8e\x15Y[\xfex\xa0\xb6U\xfa+8\xfck\xbc\xbd\x96<\xc1\x88\x99\xf3\x94\x9b\xc438\xfc\x0b\\$N\xd0\xf2,C\xba\x17V\x07\xfc-\xe6\xe1\xf0\xbf\xf3\xf6o\xb7\x9c\xc3\x02\xb4\xcbC\xc4\xd3b\xb1b\xe0%h\xe1\xf0\xcf\xb9\xb5S\xba\xb1\xe5\xb3v\x9b\xcb\xf2\xed<\x0e\x0e\xff\x9c\x8f68\x1c\x0e\x87\xc3\xe1p\xf8\x7f\xe1?v\xf5\xeb\xd7Ta4\xa8\x00\x00\x00\x00IEND\xaeB`\x82'

我不确定,但这些数据看起来很可疑,我无法使用在线工具将其转换为图像。

根据上面提交的代码,我认为:

我认为以二进制形式存储数据时存在一个错误。

如果您有任何建议或帮助,我将非常感激。甚至可能是与我在这里想到的不同的解决方案。先谢谢你了

编辑:

我尝试将二进制数据重建为图像:

            image=Image.open(BytesIO(img_binary))

            image.save("reconstructedQR.png","PNG")

重建的图片正在工作,所以问题不在于数据。

现在我将尝试找出问题是否出在将二进制转换为图片的前端。

编辑2:

我发现收到的响应数据有一点错误: 开头有

b'
,结尾有
'
,它们来自 python 二进制类型。所以我删除了它并尝试使用这些二进制数据。 我用条纹它:

const binaryDataString=response.data.qr.substring(2, response.data.qr.length - 1);

此操作成功,但

blob
中转换后的数据已损坏。 现在我需要找出如何从这些数据中获取图像。

编辑3:

我选择了一种不同的传输方法,即base64:

img_binary=base64.b64encode(img_data.getvalue()).decode('utf-8')

现在我必须对其进行解码并显示在前端:

console.log("resp: ",response.data.qr);

const binaryDataString=atob(response.data.qr);
const blob = new Blob([binaryDataString]);
const url = URL.createObjectURL(blob);

setQRCode(url);

当我尝试解码控制台记录的

cyberchef
中的数据时。 PNG文件很好,里面有我想要的二维码! 但是创建 blob 并将其放入 url 不起作用并说数据已损坏。

编辑4:

我发现了问题。 前端将 Base64 转换回二进制数据时存在问题。 我保存了这些转换后的数据,并将其与后端发送的原始数据进行比较,发现字符上存在一些差异,例如:

‰PNG 
-->
PNG 
&IDATxœíÚKr¬0 
-->
IDATxíMnë8 

还有更多...... 所以我需要找出如何在没有这些差异的情况下转换它。

python web-applications binary backend qr-code
1个回答
0
投票

解决方案:

我发现了这个 Stackoverflow,其中解决了在 JavaScript 中从 base64 创建 png 的问题:

堆栈溢出

所以我将前端代码转换为:

        const binaryDataString=atob(response.data.qr);
        const byteNumbers = new Array(binaryDataString.length);

        for (let i = 0; i < binaryDataString.length; i++) {
          byteNumbers[i] = binaryDataString.charCodeAt(i);
        }

        const byteArray = new Uint8Array(byteNumbers);
        const blob = new Blob([byteArray], {type: 'image/png'});
        const url = URL.createObjectURL(blob);

        setQRCode(url);

只是为了将其放在一个地方(答案)有后端:

            img_data=BytesIO()
            img_data.seek(0)
            img.save(img_data) 
            img_data.seek(0) # set BytesIO pointer to the begining
            img_binary=base64.b64encode(img_data.getvalue()).decode('utf-8')

            return Response({"qr": (img_binary) }, status=status.HTTP_200_OK)

这对我来说是可行的解决方案。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.