前端为什么会有service层
发布于 5 年前 作者 gyj1278 5574 次浏览 来自 问答

用户——>Client(浏览器)——>service(用来请求后端的数据)——>backend,其中client和service是一体的。遇到一个问题,backend的数据返回给了service,service把数据返回给client,由于client的网速很慢,导致用户看到了client报出的超时错误。 问题:

  1. 为什么需要service层(我们老大解释说,为了统一。还能避免跨域请求的问题);
  2. client和service的代码是一体的,一个服务,它的代码怎么知道哪些是在浏览器执行,哪些是在node执行呢?
12 回复

第一个问题,你所说的 service 应该指的是 BFF 粘合层,可以看下:为什么互联网公司开始用node.js做web服务的中间件?有什么好处吗?

场景嘛,随便举一个,如果前端有一个界面,需要同时请求后端 10 个接口,你觉得有没有问题?

第二个问题,代码放在一个仓库下,不代表它们运行的容器是一样的,client 代码其实是会通过 server 的一个 static 的服务,提供出去的,从这个问题可以看出你对前后端的概念还了解的不多,需要去补下知识,譬如看看 图解 HTTP 这本书?

@atian25 我不太喜欢BFF这种说法啊,我比较喜欢把它理解做一个bus,或者gateway

@atian25 我一直在做后端开发,简单来说就是写接口给前端调。第二个问题,看起来就像是自己调自己。

@atian25 看了你的那个问题,我做的事情包括BFF啊。。。

首先要明确一点是:一千个系统有一千种架构,都是因地制宜的。并不是说有一个万能架构可以套用在所有系统上,选择最适合的架构设计来解决实际问题才是合理的。

前端和后端、客户端与服务端,他们都是彼此相对存在的,一个名字在不同的环境下可能代表不同的东西。比如对于广义上的服务端来说,可以采用MVC思想来设计,那么View其实是可以看做是服务端的前端的;再看广义上的客户端,比如用Angular开发的网站,HTML模板部分可以看做是前端,而数据处理和HTTP通信的部分可以看做是后端;又看通常的微服务的设计上,提供接口的可以称为服务端,调用接口的不管他是一个APP、网页还是另一个微服务,我们也都可以在这种语境下称它为客户端。

楼主描述的应该就是在网站客户端系统内的语境下,页面样式部分是“client”,数据处理与HTTP请求的部分是“service”,这只是抽象概念上的名称而已,实际上所有代码都是在浏览器上执行的,没有在node上执行的,并不是说提到“service”就一定指的是广义上在服务器上跑的哪种Web服务。

拥有多个客户端产品的企业,可能会在不同客户端上应用不同的中间件,比如不同的认证策略,但是同一个核心功能又可能需要同时提供给多个客户端,那么传统的做法是在服务端上给每一个客户端写一个单独的接口,这样在小规模项目上是合理的,但是项目规模大了之后,特别是不同客户端由不同团队运营的情况下,服务端接口的复杂度会变得非常高,解决这种复杂度的一种思路就是讲不同的部分移交给各端团队自行处理,服务端只提供公共业务,而移出来的部分又往往不适合在客户端直接做,还是需要在服务器上做,那么API Gateway的概念就出来了。 每个客户端都可以设立一个自己的API Gateway,上面可以挂载这个客户端的业务需要用到的中间件,比如身份认证,后面是直接映射到通用服务端的接口,适用于简单的业务拆分场景。

如果业务拆分场景比较复杂,比如客户端希望一个页面上的数据用一个接口就全拿到,但这些数据可能在不同的服务端系统上,这时候就可以采用BFF的思想,专门为这个客户端做一个后端,后端把底层多个服务端的接口数据聚合成一个接口提供给客户端。

以上都是在有实际需求的情况下选用合适的架构思想,并不是说最好所有项目都要有Service层,对于某些企业的业务场景来说,业务可能主要在客户端上,比如游戏、工具型应用等,对于他们来说其实是不需要有一个真正意义上的服务端的,往往只是需要一个云端的存储空间而已。

@libook 感谢答主,我整理一下思路。

@libook 我说的client确实是指浏览器,页面部分是基于vue开发的;我说的service层其实就是向backend发送http,拿数据,数据是在backend处理好的。看了BFF的说法,我感觉我所说的backend就是BFF,因为我们的backend是调数据组的接口拿数据,然后处理好,给前端展示。我们的逻辑是:浏览器——>(http)service——>(http)backend(BFF)——>(http)数据接口。service可能会调用好多个backend(微服务),这种做法可以肯定的一点是应该会避免跨域问题。不知道我有没有说清楚。

@libook 浏览器和service的代码是一体的,同一个服务,我始终任务这个服务应该是用了两个端口,一个是浏览器用的端口,一个是service用的端口。

@gyj1278

从你的回复中还是不能确定到底架构是如何的。看起来好像是浏览器上运行网页,网页会发HTTP请求给service,service又会发HTTP请求给backend,backend又会发请求给数据接口,一共是1个浏览器端程序和3个服务端程序。

从网络层来看,你有两个端,一个是浏览器端,另一个是服务器端,浏览器端上运行Vue代码,service、backend、数据接口都跑在服务端,是这样吗? 还是说,浏览器端是一个网站程序,网站内部逻辑上可以分为页面和service,服务器端是backend和数据接口两部分;service负责发请求给backend,backend负责作为BFF转发请求给数据接口。

如果是为了避免跨域而放在一起,那么网页静态文件和网页使用的动态服务接口应该是同一个端口,因为端口也是确定是否是同一个“域”的条件之一。

比如: GET https://domain.com:8080/dashboard.html 是网页文件 GET https://domain.com:8080/userList 是用来获取用户列表的服务接口

这样才能避免跨域限制。

@libook 我个人认为是你说的第二种,浏览器端是一个网站程序,内部可以分为页面和service,vue的路由注册是用vue-router,service的路由注册是用express(端口是9000)。感觉service是不是可以看作代理啊。是可以直接拿postman调用service上注册的路由。这里浏览器和service的代码是通过webpack打包的,所以我的理解是,虽然代码是融合在一起的,但是用了两个端口,浏览器默认的80端口和service的9000端口。为什么这样做,有什么好处,就是我标题中提的问题了。(ps:我是按照自己的理解说的,不一定对。)

@gyj1278 你后面的描述看起来像我说的第一种,如果是第二种的话,service部分也是跑在浏览器上的。 网页用80端口,API用9000端口,这两个一定不是同一个“域”,会触发浏览器的跨域限制,没办法解决跨域问题。

业界通用的方案有两种:

  1. 前端和API用同一个域(包括相同的端口号),用不同路径区分前端资源还是API,比如静态资源的路径是/,不包括/api/,而API使用/api/*。
  2. 前端和API不在同一个域,比如网站静态资源在CDN服务器的域上,API在自己服务器的域上,然后在API服务器上配置一个允许CDN的域访问的Header。

@libook 非常感谢老哥的回答,可以说是回答的很清楚了。我build之后,启动代码,浏览器和service用的的确是同一个端口,也就是用不同路径区分是前端还是API,但是有很多代码的运行环境应该是nodejs,不是所有的代码都在浏览器执行,比如express的部分。

回到顶部