Home > Article > Web Front-end > An article analyzing nodejs middleware through practice
The emergence of
nodejs
has brought unlimited possibilities to the front-end industry, allowing many students who were originally only responsible for client development to slowly begin to contact and use the server End technology.
Although nodejs
brings many benefits, it also has its own limitations. Compared with those traditional and old programming languages, such as JAVA
,PHP
.nodejs
cannot be their substitute, and in the foreseeable future, it will be difficult to shake the status of those old programming languages. [Related tutorial recommendations: nodejs video tutorial]
Currently nodejs
mainly has the following application scenarios.
rollup
,webpack
Exploration in the engineering directionnodejs
Middle layernodejs
, such as electron
nodejs
as the back-end programming languageThis article mainly Let’s talk about some practices of nodejs
as the middle layer, see the picture below.
The traditional development model consists of the browser directly communicating with the Server The
layer communicates directly, and the addition of the middle layer means that an extra layer is added between the browser and the Server
layer.
It turns out that the client directly communicates with Server
Send a request, Server
layer receives the request and returns the result to the browser through calculation and processing.
Now the browser sends the request to the node layer
,node layer
After a round of processing, it will initiate a request to Server layer
.Server layer
will return the response result to node layer
,## after the processing is completed. #node layerFinally returns the data to the browser.
node layer,
Server layer can only focus on the business itself and ignore it. The front-end has special requirements for fields.
node layer can obtain data from the
server layer, and then calculate and integrate the data into a data format that meets the requirements of the front-end
UI. In addition, if the entire application adopts a microservice architecture, then the
Server layer will have many servers that manage separate business modules, and the
node layer will be well adapted to the microservice architecture. You can initiate requests to multiple servers to obtain data from different modules and then integrate and transform them to send to the front end.
nodejs as the middle layer.
node server, and after the request is received, the
node server You can do some processing on the request, such as changing the original path, changing the request header information, and then sending the modified request to the remote real server.
node server,
node server can still selectively process the response and return it to the browser.
node server. The following is a simple practice.
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express();//创建应用 app.use("/api",createProxyMiddleware( //设置代理转发 { target: 'http://www.xxx.com', //举例随便写的地址 changeOrigin: true, pathRewrite: function (path) { return path.replace('/api', '/server/api'); } }) ); app.use("*",(req,res)=>{ //不是以'/api'开头的路由全部返回"hello world" res.send("hello world"); }) app.listen(3000);
http -proxy-middleware is a third-party dependency package, which can be very convenient to set up proxy forwarding. It needs to be installed through
npm.
/api If it starts with , then the request will be intercepted by
http-proxy-middleware. Observe the parameters configured in
http-proxy-middleware.
represents the address of the remote real server.
is set to
true, indicating that the request will be forwarded to the
target address Above.
is to process the request path and convert
/api into
/server/api.
http://localhost:3000/api/list. Because this path starts with
/api, it will be Interception, thereby triggering the
pathRewrite function to modify the access path. The final access path becomes
http://www.xxx.com/server/api/list, and then it will be directed to this The path initiates a request and returns to the browser after getting the response.
nginx, and the forwarding is done.
如果当前请求只是想查询一下电商平台某款商品的信息,只需要将接口转发给电商平台系统即可.同理如果仅仅只是查询线下实体店某一天的销售业绩,可以直接把请求转发给线下数据系统查询,再把响应数据返回.上面介绍的插件http-proxy-middleware
支持配置多个代理路径,详细可查询文档.
现在有这么一个需求,目标是查询本周某款商品在线上和线下销售数据的对比.那么这个时候就需要node层
向两个远程服务器发送请求分别获取线上销售数据和线下销售数据,将这两部分数据聚合处理后再返回给前端.简单实践如下.
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express();//创建应用 //伪代码 app.get("/getSaleInfo",async (req,res)=>{ const online_data = await getOnline(); //获取线上数据 const offline_data = await getOffline(); //获取线下数据 res.send(dataHanlder(online_data,offline_data)); //对数据处理后返回给前端 }) proxyHanlder(app);//伪代码,将代理转发的逻辑封装起来 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
/getSaleInfo
代表着将两条数据聚合的自定义路由,如果需要聚合数据的需求比较多,这块逻辑要单独封装到路由模块中管理,并且要写在代理转发的前面.
这样就确保了需要转发的接口就交给转发的逻辑处理,需要个性化处理数据的接口就单独编写路由操作数据.
缓存对于提升系统性能,减小数据库压力起到了无足轻重的作用.一般常用的缓存软件是redis
,它可以被理解成数据存储在内存当中的数据库.由于数据放在内存中,读写速度非常快,能极快的响应用户的请求.
在node层
部署redis
管理缓存数据,可以提升整体应用性能.但不是什么数据都建议存放在redis
中,只有那些不经常变动的数据应该设置成缓存.
比如商品的信息数据,浏览器对某个商品发起请求,想查看该商品的详情.请求第一次到达node
层,redis
此时是空的.那么node
开始请求server
层得到响应结果,此时在将响应结果返回给浏览器之前,将该次请求的访问路径作为key
值,响应结果作为value
存储到redis
中.这样之后再有相同的请求发来时,先查看redis
有没有缓存该请求的数据,如果缓存了直接将数据返回,如果没有缓存再去请求server
层,把上述流程再走一遍.
redis
还可以对缓存数据设置过期时间和清除,可以根据具体的业务操作.简单实践如下.
const express = require('express'); const app = express();//创建应用 //伪代码 app.use("*",(req,res,next)=>{ const path = req.originalUrl; //获取访问路径 if(redisClient.getItem(path)){ //查看redis中有没有缓存该条接口的数据 res.send(redisClient.getItem(path)); // 返回缓存数据 }else{ next(); //不执行任何操作,直接放行 } }) aggregate(app); //伪代码,将接口聚合的逻辑封装起来 proxyHanlder(app);//伪代码,将代理转发的逻辑封装起来 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
node
做中间层可以对前端无节制的访问做限制.比如有些恶意的脚本循环访问接口,一秒钟访问几十次增大了服务器的负载.
redis
可以帮助我们实现这一功能.用户第一次访问,解析出本次请求的ip
地址,将ip
作为key
值,value
置为0
存到redis
中.
用户第二次访问,取出ip
找到redis
中对应的value
,然后自增1
.如果是相同的人重复大量访问,value
在短期内就自增到了很大的数字,我们可以每次获取这个数字判端是否超过了设定的预期标准,超过则拒绝本次请求.简单实践如下.
const express = require('express'); const app = express();//创建应用 //伪代码 app.use("*",(req,res,next)=>{ const ip = req.ip; let num = 0; if(redisClient.getItem(ip)){ //是否缓存了当前的ip字段 num = redisClient.incr(ip); //每访问一下,计数加1 }else{ redisClient.setItem(ip,0); redisClient.setExpireTime(5); //设置过期时间为5秒,5秒后再获取该ip为空 } if(num > 20){ res.send("非法访问"); }else{ next();//放行 } }) cacheData(app)//伪代码.缓存接口数据 aggregate(app); //伪代码,将接口聚合的逻辑封装起来 proxyHanlder(app);//伪代码,将代理转发的逻辑封装起来 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
在应用的前面设置一层限流中间件,每次访问来临先判端是否缓存过.第一次访问肯定没有缓存,就将当前ip
对应的值设置为0
并添加过期时间为5
秒钟.下一次相同的用户再访问时就会将value
自增1
.
最后的效果就达到了5
秒内调用接口的次数超过20
次便拒绝访问.
系统没有日志,相当于人没有双眼.日志可以帮助我们发现分析定位线上系统出现的错误.另外通过日志数据也可以进行统计计算得出某些结论和趋势.
node
层能够承担起管理日志的功能,以接口访问日志为例.在系统中新建一个日志文件夹,每次有请求访问时,首先解析请求的路径、当前的访问时间以及携带的参数和终端数据信息.然后在日志文件夹创建一个txt
文件存放当天日志情况,将上述数据和该请求的响应结果组合成一条记录插入txt
文件中.下一次访问继续走上面流程往txt
文件添加访问日志.像上面介绍的代理转发,插件http-proxy-middleware
支持配置如何返回响应结果,那么在相应的事件函数钩子里就可以同时得到请求和响应,有了这两块数据就可以存放到日志中.
这里还能制定很多的配置策略.可以选择一天一个日志文本,如果访问量巨大也可以选择一个小时一个日志文本,依据实际情况而定.
另外随着时间的延长,日志文件夹的文件内容会越来越多.这就需要编写linux
操作系统定时任务来迁移和备份这些日志数据.
日志操作简单实践如下.
//伪代码 app.use("/getList",async (req,res)=>{ const list = await getProductList(); //获取商品数据 const { 访问时间,访问路径,参数 } = req; logger.log('info',`${访问时间}-${访问路径和参数}:${list}`);//将数据存储到日志文件中 res.send(list);//将结果返回给客户端 })
中间层另外还可以做很多其他事情,比如监控、鉴权和服务器端渲染(ssr).这部分由于内容比较多可以单独成章,网络上也有大量如何实践的文章,可搜索查阅学习.
其实上面所谈到的所有功能其他编程语言都可以做到,这也成为了很多人质疑是否需要在架构上额外再加一层的顾虑.
添加nodejs
中间层,对于前端同学来说肯定是好消息.因为它能让前端承担更多的工作任务,让前端的业务比重变大.另外后端从此只需要关注自身业务,前端继续干着自己擅长的事,从整体上是能提升开发效率.
但从宏观角度上看,架构额外增加一层势必会造成整个应用性能上的损耗,另外在部署,测试层面都会增大运维成本.
当下前后端分离已经成为了主流的开发模式,很多类型的应用需要seo的支持以及首屏加载速度,因此服务器端渲染不可或缺.前端项目目前大多采用react
或vue
框架开发,如果用nodejs
承担服务器端渲染的任务,那么可以确保一套代码既可以做客户端渲染也能支持服务器端渲染,而这些工作都可以让前端程序员独立来完成.服务器端渲染技术非常重要,后面会开一个小节单独讲解.
综上来看,nodejs
做中间层最有价值的功能是服务器端渲染和接口数据聚合.如果企业应用数量较少业务简单还没有规模化,不建议添加中间层,那样反而让简单的事情变得复杂.
更多node相关知识,请访问:nodejs 教程!
The above is the detailed content of An article analyzing nodejs middleware through practice. For more information, please follow other related articles on the PHP Chinese website!