vivo 商城前端架构升级—前后端分离篇
本文主要以 vivo 商城项目的前后端分离经验,总结前后端分离思路,整理前后端分离方案,以及分离过程中遇到的问题及解决方案。
一、前言
vivo官方商城在2015年创建网上商城,开辟网络销售渠道,几年来日活和销售额持续增长,极大的助力了vivo手机的销量。
而随着业务版本迭代越来越快,业务内容逐渐增多,前后端不分离模式的弊端也逐渐显露出来,迭代效率无法跟上逐步增长的业务需求,多端扩展成本高。
为此,我们在2019年开始进行商城项目的架构升级,进行前后端分离,前端技术升级,接口规范化,以便应对未来更多的业务挑战。
二、背景
架构升级,第一步面临的问题便是前后端分离,前后端不分离的痛点已经无需赘述,既影响开发效率,又影响开发体验,但商城仍然处于业务高速发展时期,不能因为技术重构而停下业务版本的迭代。
因此业务版本迭代必须要和前后端分离同时进行,那怎么才能做到双线并行,鱼和熊掌兼得呢?方案要如何设计?如何应对技术升级带来的风险和不可控因素呢?
让我们带着这些问题来看看vivo商城是如何一步步实现前后端分离。
三、前后端分离
1、基本思路
先分析我们的业务模块,是标准的树形结构,每个功能模块包含若干子模块,每个子模块又可以包含若干更小的子模块,每个子模块对应的页面地址页类似于面包屑,形成层级包含关系,并且与功能模块的包含层级一一对应,如下图:

那如果我们能控制某个模块的页面请求,让它返回分离之后的新页面,别的请求还访问老页面,岂不是就能逐个功能模块进行分离?嗯,理论上是可行的。
比如以订单模块为例,我们可以拦截订单相关页面的请求,使得订单页面的请求访问新的资源,其他页面请求还访问老的资源,如下图:

2、逐步分离方案
那么问题来了,如何实现按访问路径去请求不同资源?商城目前的页面请求和接口请求都是通过 Nginx来做统一的门户入口,我们能否通过Nginx区分页面请求路径,从而达到路由控制的目的?
通过学习研究Nginx配置,发现 Nginx路由匹配有这样一条特性:
location 匹配首先检查使用前缀字符定义的 location,选择最长匹配的项并记录下来,如果没有匹配的正则 location 和精确匹配的 location,则使用前面记录的最长匹配前缀字符 location。
这条信息非常重要,Nginx 的 location 匹配会采用最长的匹配路径,因为我们的页面路径层级结构跟功能模块的层级结构是对应的,那我们 location匹配的路径越长,匹配的功能模块的粒度就越细,匹配的相应页面就越精确。
比如个人中心(路径为/my)下包含订单相关模块(路径为/my/order),根据Nginx最长匹配原则,就可以通过控制匹配路径长度,来控制要分离的模块的大小,比如通过拦截/my/order来拦截所有的订单相关页面。、
location /my/order {
# 匹配所有以/my/order开头的请求,其他请求不会被拦截,如/my/coupon则不会被拦截
# 如订单列表页面 https://shop.vivo.com.cn/my/order/list 会被拦截
# 将匹配到的页面请求转发到新的静态资源服务器
proxy_pass http://new-download;
}
同理,个人中心下的评价模块下面的页面路径都以/my/remark开头,那可以通过增加配置 location /my/remark {} 来拦截评价模块。当个人中心下面的子模块都分离完毕,便可以通过缩短匹配路径来扩大匹配范围。
location /my {
# 匹配所有以/my开头的请求,即个人中心的所有页面都被拦截
# 如个人中心首页 https://shop.vivo.com.cn/my 会被拦截
# 将匹配到的页面请求转发到新的静态资源服务器
proxy_pass http://new-download;
}
当所有的模块逐步完成了分离,就可以直接拦截根路径,将所有的页面请求都取新的静态资源。
3、双线并行
技术是服务于业务的,而技术的更迭演进又可以为业务带来提升,业务版本在高速迭代,犹如奋力爬升的航天飞机,而利用上述方案,便可以为飞行中的飞机更换零件甚至发动机,在业务版本迭代的同时逐步进行模块重构,业务是按版本逐步迭代的,但每次迭代一般不会涉及太多模块,而是重点针对其中一到两个模块进行迭代或者修改,当某次业务版本涉及某个模块时,我们便可以对这个模块进行分离,在分离的同时进行业务版本内容的开发,即完成了业务功能开发,又完成了模块的分离重构,而测试同学只需要测试一次,提高了版本迭代和测试效率。
当然,业务版本一般都是对一些通用模块的迭代,比如商品,结算,购物车等模块,总有一些比较稳定或者生僻的模块很长一段时间甚至一两年内都不会有大的变动,针对这种情况,就需要单独的版本进行迭代,好在这些模块并不算多,业务也相对比较稳定。
4、质量保证,风险规避
在一般的业务迭代中,只需要对某些模块代码进行修改,适配,或者补充,整个模块完全重构,无疑会增加额外的开发和测试工作量,而更多的变动和修改带来的是更多的风险和不可控因素,那怎么保证重构质量呢?
同时,业务版本策划可能只涉及此次版本业务内容,不涉及该模块的历史功能,那测试该以什么参考标准来测试这些历史功能呢,如何能保证测试覆盖率,确保所有的业务场景都能被覆盖到呢?
关于参考标准,线上标准就是最好的标准。现在网页都提供了http和https两种访问方式,用户访问的内容是一样的,在服务器配置也基本上是一样的,将https的配置改为新的配置,而http还保持不变,当用https的形式就可以访问到最新的页面,而用http形式访问的还是老页面,当然,这两个页面是可以同时访问的,因此我们可以进行新旧页面之间的对比,确保分离前后页面的一致性。
server {
listen 80;
server_name shop.vivo.com.cn;
# 老的配置不变
...
}
server {
listen 443;
server_name shop.vivo.com.cn;
# 分离模块配置
location /my {
proxy_pass http://new-download;
}
}
为了保证测试覆盖率,我们引入了代码覆盖率检查工具,精确检测某一行代码是否被测试用例覆盖。通过代码覆盖率报告,我们能很清晰的看出哪些代码被执行了,哪些分支没有被执行到,为什么没有被执行到,基于这些反馈对测试用例做调整和补充,确保全面的测试覆盖。

5、遇到的问题
(1)上线部署顺序
上线过程主要有三个部分,分别是服务端接口发布,前端静态资源发布,Nginx修改,这三个操作是有前后依赖关系的,如果顺序错了,那就会造成线上事故,因此必须严格遵守以下发布顺序:
- 服务端接口发布
服务端接口是向前兼容的,在分离过程中并不是直接在老接口上修改,而是新开了接口,保证在发布期间新老接口都是可以调用的。
- 前端静态资源发布
前端页面依赖于服务端接口,因此必须确保服务端接口已经发布完毕才可以发前端页面,否则会出现接口404的问题。
- Nginx配置修改
这一步要放到最后,如果Nginx在前端静态资源发布之前就进行了修改,那用户访问页面时就会出现页面404的情况。
(2)容灾措施
当版本上线出现问题时,如何能快速回退,且不对用户造成影响?因为我们是直接拦截用户请求并重定向到了新的静态资源服务器,那如果出现线上问题,只需要将此部分的拦截配置关闭,就可以达到快速回退的目的。而服务端接口是向前兼容的,因此无需后退。

四、结果
根据这个方案,我们经过一年时间的逐步迭代,迭代8个版本,终于完成wap端的前后端分离,可以让专业的人做专业的事。现在回过头来看看,这次技术升级我们到底解决了什么难题,而它又为我们带来了什么提升和正向作用呢?
- 纯前端业务上线发布速度提升10+倍
- 释放研发人力,专业的人做专业的事,开发效率最高提升1倍
- 打好native化、多端渠道拓展基础
- 积累技术经验、赋能更多业务
五、总结
整个前后端分离过程漫长而曲折,在这个过程中我们面临的最大问题就是如何在人力成本,业务需求和技术升级之间取得一个平衡点,这对我们来说是很有挑战性的一个难题,很多时候技术问题都可以找到参考和解决方案,但如何能在复杂的人力,资源,版本,技术积累情况下制定技术方案,兼顾各方,去主动推动解决问题,提前识别和规避风险才是对我们真正的考验。
作者:vivo官网商城前端团队
vivo 商城前端架构升级—前后端分离篇的更多相关文章
- Nginx部署前端代码实现前后端分离
实现前后端分离,可以让前后端独立开发.独立部署.独立单测,双方通过JSON进行数据交互. 对于前端开发人员来说,不用每次调试都需要启动或配置Java/Tomcat运行环境:对于后端开发人员来说 ,也不 ...
- 通过nginx部署前端代码实现前后端分离
实现前后端分离,可以让前后端独立开发.独立部署.独立单测,双方通过JSON进行数据交互. 对于前端开发人员来说,不用每次调试都需要启动或配置Java/Tomcat运行环境:对于后端开发人员来说 ,也不 ...
- 「newbee-mall新蜂商城开源啦」 前后端分离的 Vue 版本即将开源
新蜂商城 Vue 版本 2019 年 10 月份我在 GitHub 开源仓库中上传了新蜂商城项目的所有源码,至今已经有小半年的时间了,感兴趣的可以去了解一下这个 Spring Boot 技术栈开发的商 ...
- Vue+Spring Boot 前后端分离的商城项目开源啦!
新蜂商城 Vue 移动端版本开源啦! 去年开源新蜂商城项目后,就一直在计划这个项目 Vue 版本的改造,2020 年开始开发并且自己私下一直在测试,之前也有文章介绍过测试过程和存在的问题,修改完成后, ...
- [原创]一种专门用于前后端分离的web服务器(JerryServer)
如果你还不了解现在的前后端分离,推荐阅读淘宝前端团队的前后端分离的思考与实践 1.问题 随着现在整个软件开发行业的发展,在开发模式上逐渐由以前的一个人完成服务端和前端web页面,演变为前端和后端逐渐分 ...
- 超简单工具puer——“低碳”的前后端分离开发
本文由作者郑海波授权网易云社区发布. 前几天,跟一同事(MIHTool作者)讨教了一下开发调试工具.其实个人觉得相较于定制一个类似MIHTool的Hybrid App容器,基于长连的B/S架构的工具其 ...
- 前后端分离时代,Java 程序员的变与不变!
事情的起因是这样的,有个星球的小伙伴向邀请松哥在知乎上回答一个问题,原题是: 前后端分离的时代,Java后台程序员的技术建议? 松哥认真看了下这个问题,感觉对于初次接触前后端分离的小伙伴来说,可能都会 ...
- Flask & Vue 构建前后端分离的应用
Flask & Vue 构建前后端分离的应用 最近在使用 Flask 制作基于 HTML5 的桌面应用,前面写过<用 Python 构建 web 应用>,借助于完善的 Flask ...
- nginx 前后端分离 代理转发,解决跨域问题
场景 适用于公司有前端,项目采用前后端分离.类似于我们 后端 springboot 提供接口,前端专门写html调用相应的接口,解决跨域问题 配置说明 worker_processes 1; even ...
- 前后端分离之Web前端架构设计
架构设计:前后端分离之Web前端架构设计 在前面的文章里我谈到了前后端分离的一些看法,这个看法是从宏观的角度来思考的,没有具体的落地实现,今天我将延续上篇文章的主题,从纯前端的架构设计角度谈谈前后端分 ...
随机推荐
- AntDesignBlazor示例——创建列表页
本示例是AntDesign Blazor的入门示例,在学习的同时分享出来,以供新手参考. 示例代码仓库:https://gitee.com/known/AntDesignDemo 1. 学习目标 使用 ...
- MacOS|matplotlib 无法显示中文 解决办法
matplotlib 无法显示中文 解决办法 画图时,中文无法正常显示,如图 下载字体 点击这里获取字体 提取码: wnby 查看字体路径 在 python 环境中执行以下指令 import matp ...
- 创建一个循环写入数据有事务提交的oracle函数示例
/*创建函数*/create or replace function fnc_testtempInfo(startDate IN varchar2, endDate in varchar2) retu ...
- 5分钟安装Kubernetes+带你轻松安装istio服务网格指南
上次我跟大家简单介绍了一下Kubernetes的各个组件及其含义,本期本来计划带领大家一起学习一些常用命令,但我认为这种方式可能无法达到学习的效果.有可能你们会直接忘记,甚至可能没有兴趣去学.我也理解 ...
- NLP项目实战02:英文文本识别
简介: 欢迎来到本篇文章!今天我们将讨论一个新的自然语言处理任务--英文短文识别.具体而言,即通过分析输入的英文文本来判断其是比较消极的还是比较积极的. 展示: 1.项目界面 如下所示是项目启动后用户 ...
- Elasticsearch入门到进阶
Elasticsearch 一.Elasticsearch 是什么(中文官网)? Elasticsearch 是一个分布式的免费开源搜索和分析引擎,适用于包括文本.数字.地理空间.结构化和非结构化数据 ...
- Ubuntu部署NTP服务器和客户端
https://www.cnblogs.com/lsgxeva/p/14265513.html Ubuntu部署NTP服务器和客户端 NTP或网络时间协议是一种协议,用于将网络中的所有系统时钟同步以使 ...
- 劫持 PE 文件:搜索空间缝隙并插入ShellCode
因近期项目需要弄一款注入型的程序,但多次尝试后发现传统的API都会被安全软件拦截,比如 CreateRemoteThread.SetWindowHookEx.APC.GetThreadContext. ...
- C++面试复习总结
C++面试 本人20年3到4月内面了近十家公司,整理一下C++客户端问的多的基础问题 另:操作系统面试总结,OpenGL面试总结,计算机网络面试总结 代码到可执行程序 预处理:条件编译,头文件包含,宏 ...
- 2021-01-04:mysql里的innodb引擎的数据结构,你有看过吗?
福哥答案2021-01-04: 面试官刚开始问我看过mysql源码没,然后问了这个问题.回答B+树,过不了面试官那关. 答案来自<MySQL技术内幕 InnoDB存储引擎 第2版>第四章, ...