当前位置: 首页 > 科技观察

复盘Node项目中遇到的13+常见问题和解决方案

时间:2023-03-17 19:03:53 科技观察

13+ReviewNode项目遇到的常见问题及解决方案整理一下解决方案,避免大家继续踩坑。开始吧~1.windows和mac下设置NODE_ENV变量的问题我们都知道在前端项目中,会根据不同的环境变量来处理不同的逻辑,在nodejs中也是如此,我们需要搭建本地开发环境,测试环境,线上环境等。这时候有个解决办法就是一直设置环境变量,在package.json中的script属性中设置,如下:"scripts":{"start":"exportNODE_ENV=development&&nodemon-wsrc--exec\"babel-nodesrc\"","build":"babelsrc--out-dirdist","run-build":"nodedist","test":"echo\"Error:notestspecified\"&&exit1"}从start命令可以发现,我们使用exportNODE_ENV=development来定义开发环境的环境变量。由于笔者使用的是mac电脑,所以我们可以使用export来定义一个node环境变量,但是我在和朋友开发项目的时候,发现执行yarnstart后会报错。看了报错信息,发现是window下export不识别。后来笔者发现window可以使用set来定义环境变量,所以对于window用户来说,如果使用上面的方法设置NODE_ENV,可以使用如下方式:"scripts":{"start":"setNODE_ENV=development&&nodemon-wsrc--exec\"babel-nodesrc\""}2.执行npminstall没有de-gyp报错的问题有时在项目开发过程中,拉取新的node项目代码,执行npminstall后,会报如下错误:node-gyp是node环境生??成不同编译器时使用的项目文件针对不同的平台。如果遇到同样的问题,我们可以采用如下解决方案:npminstall-gnode-gyp或者直接删除package-lock.json或者yarn.lock,然后重新安装yarninstall或者npminstall。笔者亲测有效。3.node+删除koa2项目中设置的cookies的解决方案由于HTTP是无状态协议,所以需要cookies来区分用户的身份。我们可以把cookies看成是浏览器和服务器共同实现的一种规范。cookie的处理分为以下3步(基础知识和重要知识):服务端发送cookie给客户端,浏览器保存cookie(后端可以设置expires或maxAge,以a的形式存在session)每次浏览器都会将之前设置好的cookies发送给服务器。在开发node后台项目时,我们经常会涉及到用户管理模块,也就是说我们需要对用户的登录状态进行管理,在用户退出时及时删除用户的cookie。好在koa2自带了cookie处理工具Method,我们可以通过如下方式设置cookies:router.post(api.validVip,asyncctx=>{ctx.cookies.set('vid','xuxiaoxi',{maxAge:24*3600*1000});});上面我们随机设置了一个有效期为1天的cookie。如果业务发生变化,我们需要在有效期内清除这个cookie,我们该如何处理呢?分析给出一个比较好用的方案:ctx。cookies.set('vid','',{maxAge:0});此时,客户端的cookie将在下次请求时自动失效。4.socket.io如何与koa/egg一起工作?我们都知道完整的套接字。io通信由两部分组成:socket.io集成(或安装)在NodeJSHTTP服务器客户端库socket.io-client加载在浏览器端如果我们直接使用koa或egg,我们需要在内部集成http兼容使用socket.io,所以我们可以这样处理它:')(server);//正常业务处理//ioio.on('connection',(socket)=>{console.log('auserconnected');socket.on('docload',(msg)=>{console.log('docload',msg)io.emit('getData',users)})});server.listen(3000,()=>{//...});通过以上方法可以让koa和socket.io正常兼容。以后就可以正常开发IM应用啦~5。nodejs第三方模块依赖特定node版本导致的错误解决方法之前也遇到过。主要原因是第三方对node版本没有很好的向后兼容。这时候解决方法是更新这个第三方包到最新版本(如果还在维护的话),或者使用node包管理工具(n)切换到适配的node版本,如下://updatethelatestpackagenpmixxx@latest//使用包管理工具nnpmi-gn使用n来管理node版本非常方便。如果您有兴趣,可以尝试一下。6.如何在nodejs中创建定时任务定时任务是后端开发中非常常见的功能之一。在后台自动执行相应的任务。java、PHP等后台语言对定时任务有丰富的支持。对于nodejs这个后起之秀,虽然没有这么成熟的生态,但是定时任务的模块还是有的,比如node-schedule。NodeSchedule是一个灵活的Node.js类似cron和非cron的作业调度程序,它允许我们使用可选的重复规则安排作业(任意函数)在特定日期执行。它在任何给定时间仅使用一个计时器(而不是每秒/分钟重新评估即将到来的作业)。一个很实际的场景是,我们想让节点程序在每年的双十一或者双十二自动抓取某电商公司的“商品羊毛”,推送到我们的邮箱中。这个时候,我们就可以使用NodeSchedule来启动一个定时任务来执行我们的业务操作。作者的很多节点应用都采用了类似的模型。有兴趣的可以互相交流。什么是cron式调度?github上有简单介绍:所以我们可以这样写定时任务:letschedule=require('node-schedule');lettestJob=schedule.scheduleJob('42****',function(){console.log('以后会在每个时刻的42分钟执行这段代码,比如22:42、23:42');});7.在nodejs项目中使用import、export和decorator@decorator语法我们都知道现在nodejs版本已经到了14.0+版本,对最新的es语法支持的已经足够好了,但是还是有一些语法不支持,比如es模块导入导出(import,export),装饰器(@decorator)等,这时候我们需要在项目中添加要使用这些新特性,就得借助工具。这里我使用babel7来解决上面的问题,如下:#.babelrc{"presets":[["@babel/preset-env",{"targets":{"node":"current"}}]],"插件":[["@babel/plugin-proposal-decorators",{"legacy":true}],["@babel/plugin-proposal-class-properties",{"loose":true}]]}我们只需要在项目根目录下创建写入上述文件,并安装babel对应的模块,如下:yarnadd@babel/cli@babel/core@babel/node@babel/plugin-proposal-class-properties@babel/plugin-proposal-decorators@babel/preset-env这时候你可以像写前端项目一样使用这些语法新特性~8.在nodejs中优雅的处理json文件,提升json阅读而写Performance其实在nodejs优化方面有很多讲的。这里主要说一下json相关的优化方案。我们需要从两个方面进行优化。一是json文件的读写性能。这时候我们可以使用fast-json-stringify来大大提高json的读写速度。它的本质是提供了一套json-schema约束,让json结构更加有序,从而提高json的读取和查询速度。以下用法:constfastJson=require('fast-json-stringify')conststringify=fastJson({title:'H5DooringSchema',type:'object',properties:{firstName:{type:'string'},lastName:{type:'string'},age:{description:'Ageinyears',type:'integer'},reg:{type:'string'}}})比如H5-Dooring的后台有很多接口需要经常读写json数据。这时候使用fast-json-stringify会大大提高读写性能。另一方面,我们在节点端操作json。如果我们用原生的写法,会很麻烦。这个时候我们最好自己封装json的读取来提高代码的简洁性,或者我们直接使用第三方库jsonfile来方便的读写json文件,如下:constjson=require('jsonfile')constfileName='h5-dooring.json'constjsonData=jsonFile.readFileSync(fileName)9.nodejs读取大文件报错的解决方案在nodejs中,我们可以使用两种方式来读写文件,如下:fs.readFile()一次性将文件读入内存,如果文件过大,节点内存不足,报错fs.createReadStream()是以文件流的形式读取的,所以此时不??用担心文件的大小。从上面的介绍我们可以看出,如果我们要读取的文件可能非常大(比如视频这样的大文件),那么一开始就必须使用fs。createReadStream(),其实如果我们需要分析文件,比如resumes等文件逐行提取关键语料,我们可以使用node的readline模块,那么我们就可以逐行读取解析文件,以下情况:constfs=require("fs");constpath=require("path");constreadline=require("readline");constreadlineTask=readline.createInterface({input:fs.createReadStream(path.join(__dirname,'./h5-dooring')),});readlineTask.on('line',function(chunk){//读取每一行数据});readlineTask.on('close',function(){//文件阅读结束的逻辑}10.如何在nodejs中开启gzip来优化网站性能在nodejs中开启gzip的操作也是node性能优化的一部分,经过这样的处理,我们的网站可以加载的更快,我们可以使用koa-compress的koa中间件实现gzip功能,具体实现如下:importkoafrom'koa';importcompressfrom'koa-compress';constapp=newkoa();//opengzipconstoptions={threshold:2048};应用程序使用(压缩(选项));当然koa-compress也有很多自定义的配置项,大家可以感受下。11、解决window和linux系统下路径分隔符不一致的问题。这个问题也是系统之间的差异造成的,也是需要考虑的问题。我们都知道Linux系统下路径的分隔符是/,比如h5-dooring/src/pages,但是window下解析的路径可能是h5-dooring\\src\\pagespath,这个时候我们需要做适配,否则难免会部署到不同的系统报错,所以需要全局配置path通配符。作者的解决方法如下:importosfrom'os'const_$=(os.platform().toLowerCase()==='win32')?'\\':'/';这时候我们可以用_$来代替具体的路径。上面的代码使用了node的os模块。有兴趣的可以研究一下,我们可以使用os模块来处理很多由于系统差异引起的有趣问题。12、nodejs如何实现父子进程通信由于nodejs是单线程的,但是有时候我们需要支持处理多进程的业务,目前nodejs可以通过父子进程的模式来模拟多进程,我们可以使用child_process,大体流程如下:之前笔者分享的很多node实战项目都使用了child_process,大体实现流程如下://child.jsfunctioncomputedTotal(arr,cb){//耗时计算任务}//与主进程通信//监听主进程信号process.on('message',(msg)=>{computedTotal(bigDataArr,(flag)=>{//向主进程发送完成信号process.send(flag);})});//main.jsconst{fork}=require('child_process');app.use(async(ctx,next)=>{if(ctx.url==='/fetch'){constdata=ctx.request.body;//通知子进程开始执行任务,并传入数据constres=awaitcreatePromisefork('./child.js',data)}//创建异步nousthreadfunctioncreatePromisefork(childUrl,data){//加载子进程constres=fork(childUrl)//通知子进程开始workdata&&res.send(data)returnnewPromise(reslove=>{res.on('message',f=>{reslove(f)})})}awaitnext()})13.节点端实现图图像编辑/压缩图像编辑和压缩在许多使用前端技术的场景中很常见。事实上,有很多图像需要在节点端进行处理。毕竟客户端处理的质量不好控制。这时候我们就可以使用node-images了。它是一个用于node.js的轻量级跨平台图像编解码器库。其主要特点如下:轻量级:无需安装任何图像处理库跨平台:编译后的.node文件在Windows下发布,下载后即可使用。易于使用:jQuery风格的API,简单可靠。我们可以用它来裁剪和压缩图像。基本用法如下:constimages=require("images");images("input.jpg")//加载图片文件.size(400)//按比例缩放图片到400像素宽.draw(images("logo.png"),10,10)//在(10,10)绘制Logo.save("output.jpg",{//保存图片到文件,图片质量为50quality:50});在H5-Dooring编辑器中,您还可以使用它来进行图片处理和编辑,您也可以根据实际业务使用。14、节点端解析“命令行指令串”实现在线自动打包部署项目。关于node解析cmd字符串和执行命令行指令的方式,笔者在自己实现自动化工作流一文中也有介绍,使用child_process模块??的exec,具体实现可参考文章:基于NodeJS从零开始搭建在线自动化打包工作流程(H5-Dooring特别版),这里写一个简单的例子:constcmdStr=`cd${outWorkDir}&&yarnbuild${fid}`//解析命令Exec(cmdStr,function(err,stdout,stderr){if(err){console.log('apierror:'+stderr);io.emit('htmlWorked',{result:'error',message:stderr})}else{//...}})15。如何解决节点应用崩溃、负载均衡和进程管理解决这个问题最好的方法是使用pm2或者forever,它提供了强大的节点进程管理、负载均衡能力,以及一定程度的应用监控,推荐使用在线环境下的pm2来管理我们的节点应用。