当前位置: 首页 > 后端技术 > Node.js

使用Docker和Node快速实现一个在线二维码解码服务

时间:2023-04-03 12:28:40 Node.js

本文使用《Signature4.0International(CCBY4.0)》许可协议,欢迎转载,或重新修改使用,但需注明出处.Signature4.0International(CCBY4.0)本文作者:苏洋创建时间:2018-12-09字数:5453字阅读时间:11分钟阅读链接:https://soulteary.com/2018/12...使用Docker和Node快速实现在线二维码解码服务。本文将介绍如何使用Docker、Node、JavaScript、Traefik完成一个简单的二维码解析服务。整个代码在300行以内。最近跟折腾文章有关的事情很多。其中,有一个现代元素其实也是挺麻烦的,那就是二维码。无论是“生成动态和静态二维码”还是“分析已经生成的二维码”,其实都不难实现。只是在日常工作中基于命令行操作不方便。于是花了一些时间实现了一个简单的QRCode在线分析工具。完成这个工具后,原来需要“打开终端,定位文件,执行命令,等待结果”简化为“打开网页,CTRL+V粘贴,稍后显示结果”,的当然,因为它提供了一个额外的接口,所以它也可以作为一个无状态的服务来使用。实现服务端核心解析逻辑核心逻辑其实很简单,就三行伪代码为例。constuploadContentByUser=req.body.files;constdecodeContent=decodeImage(uploadContentByUser);constresult=decodeQR.load(decodeContent);但在实际使用中,为了性能,我不会过度使用新语法进行代码封装,更倾向于尽可能使用“原生”的回调方式进行异步编程,避免各种“包装器”造成不必要的损失”。因为最终目标是“在浏览器中进行一次粘贴/拖动操作就完成了”。因此,我们需要对上述核心逻辑进行扩展。按照“简单项目不要过度封装”的思路,下面将代码展开到30行左右。app.post('/api/decode',multipartMiddleware,function(req,res){letfilePath='';try{if(req.files.imageFile.path)filePath=req.files.imageFile.path;}catch(e){returnres.json({code:500,content:'requestparamserror.'});}fs.readFile(filePath,function(errorWhenReadUploadFile,fileBuffer){if(errorWhenReadUploadFile)返回res.json({code:501,content:'读取上传文件错误。'});decodeImage(fileBuffer,function(errorWhenDecodeImage,image){if(errorWhenDecodeImage)returnres.json({code:502,content:errorWhenDecodeImage});letdecodeQR=newqrcodeReader();decodeQR.callback=function(errorWhenDecodeQR,result){if(errorWhenDecodeQR)returnres.json({code:503,content:errorWhenDecodeQR});if(!result)返回res.json({code:404,内容:'乱世佳人'});returnres.json({code:200,content:result.result,points:result.points});};decodeQR.decode(image.位图);});});});上面的逻辑很简单,主要做了以下几件事:接受用户上传的文件,读取用户上传的文件,解析用户上传的文件,尝试转换文件中的信息解码并反馈给用户,这依赖于一个快速的三方中间件multipartMiddleware。我主要用它来序列化上传文件的请求。源码非常简洁,100行左右。有兴趣的可以浏览一下。使用起来也非常简单。,无需配置,只需两行即可运行。constmultipart=require('connect-multiparty');constmultipartMiddleware=multipart();当然,为了能够配合客户端JavaScript来达到我们最终的目的,我们还需要一些额外的代码,比如:提供一个浏览器可以浏览的页面。这里补充一点,如果你用的是express-like的框架,一般会有一个静态方法,可以让你设置一个静态文件目录,可以在不编写路由逻辑的情况下,对外访问一些文件,例如:app.use(express.static(__dirname+'/static',{dotfiles:'ignore',etag:false,extensions:['html'],index:false,maxAge:'1h',redirect:false}));但是,这种情况下我其实只需要一个入口页面就可以满足需求,完全不需要外部资源,比如vue、react、jq、各种css框架……这时候我推荐使用fs将要显示的页面直接内存缓存,直接提供给用户的API,比如按照下面的代码编写,大概十行左右就可以满足要求。constindexCache=fs.readFileSync('./index.html');app.get('/',function(req,res){res.redirect('/index.html');});app.get('/index.html',function(req,res){res.setHeader('charset','utf-8');res.setHeader('Content-Type','text/html');res.send(索引缓存);});当然,如果你想在调试的时候像静态文件一样“热更新”这个文件,就需要把这个indexCache重写成一个方法,拦截用户请求后,每次动态读取文件,或者更高级一点,实现一个基于文件最后编辑时间戳的简单LRU缓存。实现客户端交互逻辑实现接口后,我们就完成了缺少的前端交互逻辑。因为这里没有繁重的操作,界面也很简单,既不需要jQ等库,也不需要Vue、React等框架,直接写脚本就可以了。补上我需要的界面,上半部分是数据交互的区域,下半部分是我的交互结果列表。由于页面上的元素不多,我们直接使用脚本来创建和操作元素。letuploadBox=document.createElement('textarea');uploadBox.id='upload';uploadBox.placeholder='PasteHere.';document.body.appendChild(uploadBox);letlist=document.createElement('ul');list.id='result';document.body.appendChild(list);浏览器端有3个核心操作:接受用户的拖拽粘贴图片,上传用户给的图片数据,分析服务端接口我们先实现第一个操作,拖拽粘贴丰富的交互功能,大概30个代码行可以解决战斗。functiongetFirstImage(data,isDrop){让i=0,item;让目标=isDrop?data.dataTransfer&&data.dataTransfer.files:data.clipboardData&&data.clipboardData.items;如果(!target)返回false;while(i-1)returnconsole.warn('文件格式不正确');formData.append('mimeType',fileType);fetch('/api/decode',{method:'POST',body:formData}).then((response)=>response.json()).then((data)=>{if(data.code===200)returnaddResult(filename,data.content);returnaddResult(filename,data.content);}).catch((error)=>addResult(filename,error));}最后,写一些样式规则,并优化解决方案分析结果显示完成,例如可以更方便的复制分析结果.nodeName.toLowerCase()==='input'){target.select();}}});functionresult(file,text){letli=document.createElement('li');li.innerHTML=''+文件+''+'';document.getElementById('result').appendChild(li);}将程序容器化仔细阅读以上文章,你会发现实际程序只有两个文件,一个是服务端的Node程序,另一个是我们的客户端页面,但其实我们还需要一个记录Node依赖的package.json和一个供用户构建容器镜像的Dockerfile,最简单的目录结构如下:.├──Dockerfile├──index.html├──index.js└──package.json考虑到实际的维护,我们还需要创建一些其他的问题,但并不重要。相关文件内容可以浏览我后面提供的源码仓库。此时,当我们执行nodeindex.js,然后在浏览器中打开localhost:3000,就可以实现我们文章开头提到的一键粘贴,完成对二维码的解析。但是为了方便部署,我们还是需要对程序进行容器化。我们重点关注容器构建文件,这个文件也很简单,几行就足够我们使用了。FROMnode:11.4.0-alpineMAINTAINERsoultearyRUNapkupdate&&apkaddyarnWORKDIR/appCOPY./appRUNyarnENTRYPOINT["node","index.js"]使用简单的构建命令:dockerbuild-t'docker.soulteary.com/decode-qrcode.soulteary.com:0.0.1'。等待一两分钟,你就可以得到一个可以在没有当前环境的情况下在任何地方运行的容器镜像。如果你想让容器运行起来,只需要一个命令。dockerrun-it-p3000:3000'docker.soulteary.com/decode-qrcode.soulteary.com:0.0.1'如果每次都用这个命令,那就麻烦了。我们不妨使用compose和Traefik来做服务。使用Traefik进行服务操作使用compose和Traefik非常简单。我在之前的文章中多次提到过,所以这里有一个简单的配置文件示例:version:'3'services:decode:image:docker.soulteary。com/decode-qrcode.soulteary.com:0.0.1公开:-3000个网络:-traefik标签:-“traefik.enable=true”-“traefik.port=3000”-“traefik.frontend.rule=Host:decode-qrcode.lab.com"-"traefik.frontend.entryPoints=http,https"networks:traefik:external:true然后使用docker-compose-fcompose.ymlup-d自动启动服务,自动注册服务即可Traefik的服务发现。如果需要扩展,scaledecode=4就够了。如果还不知道如何操作,可以看之前的文章进一步学习,:)最后附上完整的示例代码:https://github.com/soulteary/decode-your-qrcode我最近假期结束,换了新公司。手头的东西比较多,写文章的速度会慢一些,不过没关系。草稿箱里的东西积累的越多,文章的质量就会提高。让我们一起期待吧。