从之前的两篇文章当中,已经分析了我们的金翅h5加速平台,以及如何做静态资源的加速。这一章将主要集中在如何做html加速优化。
html加速优化也是所有优化手段中,对白屏时间优化效果最为明显的!
以预取html内容作缓存的方式实现加速,需要解决以下问题:
实现native端代理请求html内容,还有一个好处:从WebView.loadUrl(url)
开始,实际要先加载WebView
内核后才会真正的发起html请求。
如果native端实现代理发送html请求,则可以将WebView
内核加载与发送请求html,两个过程并行起来。在调用WebView.loadUrl(url)
同时或之前,发起html请求。这就至少节约了WebView
内核加载的这段时间(约100ms~250ms)。
Android端具体的实现,我们直接看示意代码。这里使用了OkHttp
作为网络请求库。
// 定制request header
Map<String, String> requestHeader = new HashMap<>();
requestHeader.put("method", "GET");
requestHeader.put("Host", mHtmlUrl.getUri().getHost()); // mHtmlUrl就是html的链接
requestHeader.put("Accept", "text/html");
requestHeader.put("Accept-Encoding", "gzip"); // 注意这里,如果html body以gzip的方式返回,后面读取的时候要解压缩
requestHeader.put("Accept-Language", "zh-CN,zh;");
// 设置cookie和ua这两步最为重要,大部分后台服务器需要根据这两个参数获取信息、作跳转等
requestHeader.put("Cookie", "xxx");
requestHeader.put("User-Agent", "xxx");
// 构建OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.followRedirects(false) // 不follow重定向
.followSslRedirects(false)
.connectTimeout(15, TimeUnit.SECONDS)
.build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();
// 获得response headers
Headers headers = response.headers();
// 获取html body的网络输入流
InputStream byteStream = mResponseBody.byteStream();
String contentEncoding = headers.get("Content-Encoding");
if ("gzip".equalsIgnoreCase(contentEncoding)) {
// 如果html body是gzip压缩,则解压
inputStream = new BufferedInputStream(new GZIPInputStream(byteStream));
} else {
inputStream = new BufferedInputStream(byteStream);
}
// 最终拿到了html body的inputStream供读取
iOS 端仍然是通过 NSURLProtocol 代替 Webview 请求 HTML。
request header
和response header
的处理html的内容能否正确的获取、加载,request header
和response header
必须要处理无误。
request header
这里最重要的是Cookie
及User-Agent
参数,Cookie
可以通过CookieManager
从WebView
读取; 而User-Agent
通过WebSettings.getDefaultUserAgent()
读取再附加上自己的ua值即可。
后台系统一般都会从Cookie
中读取身份、session等信息;
有赞的前端体系中User-Agent
的设置非常重要,会根据UA的值确定是跳转到PC端的网页还是H5。
response header
response header
中包括Set-Cookie
及CSP
等重要响应头信息。response header
和html body
的内容必须一起被加载到WebView
中。
在Android中,WebViewClient.shouldInterceptRequest(view, url)
返回的WebResourceResponse
提供了
void setResponseHeaders (Map<String, String> headers)
方法设置响应头(注意这个接口从api level>=21才提供) 。
在我的测试中,通过这个接口设置的响应头,Set-Cookie
似乎一直没有生效,所以我们还是采用了CookieManager
来手动设置:
List<String> cookies = headers.toMultimap().get("Set-Cookie"); // headers即从`OkHttp`返回response header对象
CookieSyncManager.createInstance(context); // 这句一定得调,否则在一些低端机型上有莫名崩溃
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
for (String cookie : cookies) {
cookieManager.setCookie(url, cookie);
}
// 另注:上述设置response cookie的代码不能在shouldInterceptRequest中调用,需要异步化。
// 参考:https://issuetracker.google.com/issues/36989494#c8
在 iOS 中,Request Header 可以从 NSUserDefault
中读取,另外再拼上自定义的请求头即可。而 Response Header 则在 NSURLProtocol 代替 WebView 请求的过程中可以拦截到。响应头的使用又可分为两种。
这样处理可以保证缓存数据也有正确的响应头。
页面发生重定向,有可能要在不同的域名下种一些cookie, 比如有赞之前的总域名是koudaitong.com
,后来是youzan.com
,在这两个域名并存的时间里,相互之间就要同步一些cookie、状态信息,以免出现走到不同模块使用了不同的域名,然后发现状态不一致而出错。
对于要求登录的页面也是,要求登录后就会跳转到登录页面,这个过程在有赞也会产生一个302跳转。
当然出现重定向的情况还有很多种,比如:短链接等。每种的情况处理起来都不太一样。
为了简单化,以及避免出现未考虑到情况造成错误。我们现阶段的html加速只对不会产生重定向的页面生效。所以在上述OkHttpClient
对象上设置了followRedirects(false)
,不follow重定向。
维护html缓存,除了保存response header
及html body
以外,应该设置其过期策略,如果一个页面已经请求到加载的时间过去太久就不应该使用本地缓存了,直接请求远端的结果。
在我们的金翅管理后台,有能够增加相应控制的配置入口:
目前设置超过一个小时的html缓存直接失效。
“缓存html链接”可以动态配置让客户端预先下载的html链接,这个适合于有活动页的场景。当然我们在金翅的客户端SDK中开放了接口供用户去配置上述所有的设置项。
再来看下我们在商品详情页和微页面使用html加速优化方案后的对比:
注:微页面的效果图是在一款低端的android机上的测试效果。背景中的转圈是h5中的实现,html的内容实际已经加载完成了,转圈是在加载、渲染静态图片资源。
搭建一整套的h5加速平台还是需要的工作量挺庞大的。好在我们从开始时就做了足够的分析,制定分步走的计划。每一阶段需要达到什么样子,最后做成什么样子,心里都清楚。
除了我们已经在金翅平台中实现过的以外,h5加速,还有许多方面可以做的。像是优化网络协议、优化html与js的实现、后台主动推送更新等等。
业界有许多优秀的实施方案,我们在做的过程中吸取了很多经验。
文章附录如下:
欢迎关注我们的公众号
Original url: Access
Created at: 2019-09-26 18:06:12
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论