分布式系统架构:技术栈详解与快速进阶
上QQ阅读APP看书,第一时间看更新

2.4 前后端交互优化

前后端交互会重点关注数据传输、请求交互方式等,可从这几个方面来分析如何优化:请求方式优化、页面静态化、分批次请求、页面缓存、网络传输、页面渲染。具体优化方案如下。

1. 请求方式优化

目前在页面使用HTTP请求数据,常用请求包括GET、POST、PUT、DELETE、TRACE、OPTIONS、HEAD。

  • HEAD:用于在不传输整个响应内容的情况下获取包含在响应消息头中的Head信息。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URI所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。

由于GET请求无须转换,请求方式上要比POST高效,但是GET请求传输内容很少,默认1024B,而POST请求有2MB,所以GET请求更适合简单查询。POST请求由于传输内容较多,且POST请求浏览器不显示参数,安全性高于GET,所以POST请求更适合复杂业务场景,如增/删/改/复杂查询。

GET容易受攻击、POST请求会预检请求,浏览器会检查服务器端是否支持跨域,检查通过后再真正提交数据。

客户端请求服务器端时,请求的方式可以根据系统的规划,合理使用,提高请求效率。

2. 页面静态化

与JSP类似的动态网页在需要进行数据查询时,若访问量增加,查询的频率也随之增加,会占用很多资源,直接影响整个页面的访问速度。

页面静态化,指前后端分离,前端用HTML构建,通过JS动态与服务端交互。页面静态化后,当访问量增加时,只要请求接口高效,占用的资源就很少,整个过程不会对脚本进行重新获取和计算,从而提高了访问速度。

页面静态化特性如下。

  • HTML容量体积小,占用磁盘空间相对较少,由于是静态页面,没有强依赖,部署范围广;
  • HTML可以部署在CDN上,用于加速站点访问;HTML可以横向部署多份,支持负载均衡,分担压力。

例如,在客户端部署一个节点,高峰期间能承受的吞吐量是200,1s可以处理200个请求,页面静态化后通过JS去请求服务器。在相同条件下,服务器不会计算页面的状态效果,充分利用有效资源,可容纳处理更多请求。通过统计分析,如发现页面访问人数增加导致页面加载静态资源过多,出现缓存、卡顿等情况,可在客户端部署多个节点,把不同流量负载到不同节点中去,以提高页面访问效率。

与此同时,页面还可以部署到CDN云端,其目的是通过在现有的Internet中增加一层新的网络架构,将内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,解决网络拥挤的状况,提高用户访问网站的响应速度,从技术上全面解决网络带宽小、用户访问量大、网点分布不均等原因所造成的用户访问网站响应速度慢的问题。

3. 分批次请求

由于客户端请求服务端的数据量有限,一次请求过大的数据会给网络传输带来较大的影响,此时可以把请求拆分,合理设置同步或者异步,分批次多次请求,以缓解网络传输的压力。

分批次请求可以有效减少数据量过大导致的卡死或页面崩溃等现象。比如,获取某个城市的完整导航数据,很多人喜欢一次性获取完毕,但由于测试不充分,在高流量情况下,很容易在传输的数据量过大时出现各种棘手问题等。对于这种情况,可在设计阶段有意识去规避此类问题,根据不同维度合理拆分导航数据,同时还要考虑不同维度产生的最大传输交互的数据量大小,不能超过HTTP请求的最大限制,单次请求最好控制在500KB以内。尽量将数据量精简后再传输,如精简后仍过大,可适当拆解。

4. 页面缓存

充分利用浏览器本身缓存和HTML静态页面缓存,可以减少请求数据的频率,加快响应速度。

浏览器本身缓存指发起请求客户端到执行功能的服务器之间用来保证服务器输出的副本,并提供给发起请求的客户端。由于减少了请求频率,服务器端处理能力得到提升,以同样的资源条件可容纳更多、更大的访问量和并发量。

通常,可对存放缓存中的数据设置时效,通过时效减少浏览器分解能力。因此要对缓存中的内容做有效性检查,也称“重验证”,以保证缓存中的内容和服务器一致。其运行的工作机制是通过HTTP头部增加Last-Modified、If-Modified-Since、Expires、Cache-Control等标识,可同服务器进行商定,以确认浏览器是否缓存。服务器端返回HTTP头部设置Expires,Cache-Control:max-age,客户端会优先处理max-age。

浏览器会自动缓存静态资源(CSS、JS、Img),缓存策略如Modified、If-Modified,并判断服务器文件是否改动,重验证自动获取新的内容缓存。如JS使用Ajax获取后端数据,后端返回时可以设置Header头部,如Last-Modified,那么客户端在下一次请求报文中会包含If-Modified-Since,服务器端收到后会自动比较两个时间。若Last-Modified更大,表明客户端缓存中内容已超时,服务器会将最新的内容(新Header)返回客户端,状态为200,否则会认为客户端缓存中的内容是最新的,返回客户端状态304,同时包含最新Header头部信息。

设置缓存LocalCache类的方式如代码清单2-8所示。

代码清单2-8 LocalCache类代码

// 充分利用缓存,max-age>0时直接从浏览器缓存中提取,max-age<=0时向服务器端发送HTTP请求确认, 查看该资源是否有修改,有的话返回200, 无的话返回304,而响应头的Cache-Control:max-age:是通知浏览器在多少秒时间范围内从缓冲区刷新
    response.setHeader(“Cache-Control”:“max-age=100”)。
    // 禁止缓存,浏览器可能会缓存,需要检查服务器一致
    response.setHeader(“Cache-Control”:“no-cache”);
    // 禁止缓存,浏览器删除缓存内容
    response.setHeader(“Cache-Control”:“no-store”);
    // 过期时间
    response.setDateHeader(“Expires”:-1)
    // 过期时间
    response.setDateHeader(“max-age”:0);

注意,F5和Ctrl+F5刷新实现也有差异,F5让浏览器去执行一次一致性检查,而Ctrl + F5删除本地缓存后会再去执行一次一致性检查。

浏览器用缓存,那么静态资源更新如何主动通知浏览器缓存失效呢?

1)资源链接后面加上?“版本号”或者“时间戳”,由于浏览器是按URL来进行缓存,更新后浏览器会认为这是新的地址,会重新加载一次。

2)引入HTTP加速器,如Varnish,主动请求PURGE,让Varnish缓存资源内容失效,这样Varnish会重新获取内容,并将新内容返回客户端。

3)客户端浏览器会发起新的请求,去重验证资源是否有更新,若是按照新的连接发出的,那么服务器端没有连接对应的Etag,需要重新下载新的资源。

提示

利用CDN缓存的优点

某公司网站前后端交互及展示都需要网络,而前后端的资源部署在自己的服务器上,通过域名映射。用户是通过外网(Wi-Fi、4G)等去访问公司域名下的网站资源。CDN是分布式网络,可以把所需的内容更快地传递到服务范围内的一个具体位置,而往往这个具体位置与实际的内容服务器距离很远。比如,公司的网站主机部署在美国,而用户遍布全球,当中国用户去访问网站时,延迟会很久,而把网站前端利用CDN放到中国则会很大程度上提高用户访问网站的体验。

5. 网络传输

前后端交互过程中,发送请求到服务器端,再由服务器端处理完毕返回至客户端,其中都会存在网络传输。假如网络传输过程缓慢甚至堵塞,那我们的前后端会存在卡顿甚至假死的情况,给用户带来非常差的体验。如何提高网络传输的效率呢?具体思路如下。

1)合理设置带宽。如从1MB升级到100MB,具体根据情况而定,以加快网络的传输。

2)精简网络传输过程中不必要的内容,优化调整。

3)压缩网络传输过程中内容的大小。

4)优化网络的链路,如TCP协议。

6. 页面渲染

利用页面解析静态资源规则,把脚本文件存放在底部、样式文件存放在顶部,可减少页面渲染时间。

脚本文件存放在顶部会引发如下问题:

1)在下载脚本时会阻塞并行下载;

2)当脚本没有完全加载进来时,若用户触发了脚本事件,可能会出现JS错误问题;

3)使用脚本时,对于位于脚本以下的内容,会逐步阻塞。

样式文件存放在顶部会引发如下问题:

1)白屏;

2)无样式内容闪烁。

页面中CSS等文件要写到Head里,不要写到Body中,否则会引起重新渲染。iframe会导致重绘,要尽量减少使用数量,避免不必要的渲染,如position:fixed定位在滚动时会不停渲染,建议页面滚动时先取消hover特效,滚动停止后再加上。通过外层加类名进行控制,如border:none而不是border:0,否则会渲染。

【示例】 一个WAP公司网站,用户最先进入的是首页,通过首页可以感知到网页是否好用,访问速度是否够快等。首页什么时候加载完毕呢?在可见的屏幕范围内,内部充分展示完全(有Loading进度条的从显示到消失)才算完毕。那么如何快速展示首屏呢?有三种方案:局部按需加载、延迟加载、滚屏加载。

局部加载可以在屏幕可见范围之内,按照用户关注功能维度分块,根据关注热度依次加载。延迟加载可以让屏幕外或大的资源在整体首屏加载完毕后进行网络加载。滚屏加载是一种无刷新状态加载方式,通常适用于页面元素较多的情况,可以通过下滑、滚动等方式去触发事件然后加载资源。

如某些页面加载时间过长,可以增加Loading提示,让用户感知加载的过程,完成之后可以隐藏它。有些特殊功能可能需要等到资源加载完毕后才可以正常使用,在进度条中显示百分比可以告知用户当前进度。

首页加载完毕后,网站正常会存在很多图片、文件等,这些文件、图片如果过大会占用很大带宽。在网络不好的情况下,有些图片会很长时间都显示不出来,因此图片本身的加载也需要好的处理方式。那么如何才能更好、更快地展示图片呢?可以从以下几个方面考虑。

1)图片格式使用选择。显示效果较好的图片格式有WebP、JPG和PNG 24/32。其中WebP格式图片最小,但在App中可能会存在兼容性问题;JPG格式大小适中,解码速度快,兼容性好,页面使用比较合适;PNG格式显示的效果比JPG好,但此类大图片存在问题,应该避免使用。

2)多张图片可以通过设计全部整合到一张图片中去,通过坐标定位显示。

3)避免页面代码中大小重设,如代码width: **px,图片显示的宽度是50px,而下载图片的宽度是500px,这是不行的。使用图片的原则是需要显示多大,就下载多大的资源。

4)图片可以存到CDN云端上。

5)前后端交互的图片,如需要动态从服务器端获取展示的图片,若图片本身不大,可以用Base64的处理方式,将图片变成一串文本编码传输给页面。这种方式可以减少一次HTTP请求交互,还有效降低了传输流量消耗。

6)相关静态资源、附件等可以通过Gzip压缩,压缩后文件变少,传输更高效。