前言
为了丰富动态性,移动app一般会嵌入H5页面来实现实时操作,例如:支付,运营活动等。H5技术在扩展app功能方面占据重要地位。对于一个H5的产品,除了其实现功能是重点外,性能同样是用户体验中不可或缺的一环。H5性能的测试工具一般分为两类,一类是抓包工具,如Fiddler、Charles等;另一类是平台型工具,如PageSpeed、Chrome Devtools等。抓包类工具对于数据的展示不够直观,操作比较复杂。本文通过探索平台型工具的Chrome Devtools的实现机制,提供了基于远程调试协议的H5性能测试解决方案。
远程调试协议
Chrome Devtools是通过远程调试协议(Remote debugging protocol)与浏览器页面(pages)交互和调试。采用webSocket来与页面建立通信通道,由发送给页面的commands和它所产生的events组成。这个协议是开放的,第三方开发者也可以调用这个协议来与页面交互调试。
WebSocket通信协议介绍
WebSocket Protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信。HTTP通信协议中,服务器需要接受到客服端的请求后被动作出响应。不同于传统通信协议,WebSocket协议在建立第一次握手协议后,服务器不需要等待请求在作出响应,而是在有新数据时就主动推送给服务端,实现了客服端与服务器,客户端与客户端之间的实时通信,更好的节省了服务器资源和带宽。
一张图带你体会高效的WebSocket Protocol:
以下是WebSocket Protocol的抓包实例:
建立第一次的握手协议后,客户端和服务器之前就开始进行有效的实时通信了。
远程调试协议结构
远程调试协议基于WebSocket,利用WebSocket建立连接开发者和浏览器内核的快速数据通道。该协议把操作划分为不同的域(domain),比如Page、Rendering、Network、Memory和DOM等,通过远程调试协议发送的请求可通过域操作获取相应的信息。每个域(domain)定义了它所支持的command和它所产生的event。每个command包含了指定所要进行的操作以及操作说要的参数和描述;每个event表示了发生某个事件的监听,通过设立监听点来返回信息和进行下一步操作。command和event中可能涉及到非基本数据类型,在domain中被归为Type,比如:’LoaderId’: ,其中loaderId为非基本数据类型。下图
显示了远程调试协议network域的基本数据结构:
{
"domain": "Network",
"description": "Network domain allows tracking networkactivities of the page. It exposes information about http, file, data and otherrequests and responses, their headers, bodies, timing, etc.",
"dependencies": ["Runtime", "Security"],
"types": [{
"id": "LoaderId",
"type": "string",
"description": "Unique loader identifier."
},
..., {}
],
"commands": [{
"name": "clearBrowserCache",
"description": "Clears browser cache.",
"handlers": ["browser"]
},
..., {}
],
"events": [{
"name": "requestServedFromCache",
"description": "Firedif request ended up loading from cache.",
"parameters": [
{ "name":"requestId", "$ref": "RequestId","description": "Request identifier." }
]
},
..., {}
]
}
事实上,远程调试协议数据结构就是一种json格式的数组,可以通过json对象的方式调用其方法或事件。例如要调用network中清除浏览器缓存的方法,可以通过WebSocket协议连接到该页面后,使用WebSocket的send方法发送一个对象来实现,
ws.send('{"id": 1,"method": "Network.clearBrowserCache", "params":{}}')
其中ws表示WebSocket与浏览器建立连接后的url,id是被链接页面的id。
应用实践
了解了远程调试协议建立的通信机制和数据结构,接下来看看实战的例子——如何获取手机中H5页面的性能数据。
1.建立移动端和PC的连接,获取webSocketDebuggerUrl
手机端用chrome浏览器打开需调试的H5页面,通过USB和PC端连接,执行端口转发指令将页面发送的数据信息转发到9222端口,这样就可以在PC上操纵手机的页面。
adb forward tcp:9222 localabstract:chrome_devtools_remote
在PC端访问http://127.0.0.1:9222/json即可获得当服务端连接到该标签页的websocket地址,如下图:
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/2"即为要调试的页面
[ {
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@799386cbf7c1cbf70c12c0e593b2b2e23e39ba30/inspector.html?ws=127.0.0.1:9222/devtools/page/2",
"id": "2",
"title": "微微一笑很倾城,抽张油卡变男神!",
"type": "page",
"url": "http://202.69.27.140:13080/dmz/lottery-sd/modules/lottery-sd/1.0.0/views/index.html",
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/2"
} ]
2.初始化消息
为了获取页面传递数据,首先得建立一个初始化窗口,触发客户端和网络的连接,并建立监听的事件。
var socket = new WebSocket(url);
socket.onopen = function(event) {
//发送一个初始化消息
socket.send('{"id": 6, "method":"Network.enable", "params": {}}');
socket.send('{"id": 6, "method":"Page.enable", "params": {}}');
socket.send('{"id": 6, "method":"Page.navigate", "params":{"url":"http://202.69.27.140:13080/dmz/lottery-sd/modules/lottery-sd/1.0.0/views/index.html"}}');
//监听消息
socket.onmessage = function(event) {
console.log('Client received a message', event);
var data = event.data;
var obj = new Function("return" + data)();
//console.log(obj.method);
}
}
所有的数据操作要在这个初始化窗口内实现。
3.发送远程调试协议方法的消息
页面发送的消息要经过远程调试协议的“包装”来解析页面的性能数据。
function DoToMessage(message,page){
switch (message.method) {
case 'Page.domContentEventFired':
page.domContentEventFiredMs = message.params.timestamp * 1000;
break;
case 'Page.loadEventFired':
page.loadEventFiredMs = message.params.timestamp * 1000;
break;
default:
if (message.method.match(/^Network\./)) {
id = message.params.requestId;
switch (message.method) {
case 'Network.requestWillBeSent':
// the first is the originalrequest
if (typeofpage.originalRequestId === 'undefined' &&
message.params.initiator.type === 'other') {
page.originalRequestMs =message.params.timestamp * 1000;
page.originalRequestId =id;
}
page.objects[id] = {
'requestMessage':message.params,
'responseMessage':undefined,
'responseLength': 0,
'encodedResponseLength': 0,
'responseFinished':undefined,
'responseBody': undefined,
'responseBodyIsBase64':undefined
};
4.获取HAR文件,并进行对象的格式整理
页面向服务端发送了远程调试协议方法下的请求,服务端会返回HAR(HTTP Archive)文件,一个用来储存HTTP请求/响应信息的通用文件格式,基于JSON格式的数据。我们可以对改文件数据进行二次数据格式整理,便于后续的对象操作。例如每个输入会返回页面参数id,开始时间,加载时间,请求参数,响应参数等。
functionfromPage(page) {
for (var requestIdin page.objects) {
entries.push({
'pageref': page.id.toString(),
'startedDateTime': newDate(object.requestMessage.wallTime * 1000).toISOString(),
'time': toMilliseconds(duration),
'request': {
'method':object.requestMessage.request.method,
'url':object.requestMessage.request.url,
'httpVersion': protocol,
'cookies': [], // TODO
'headers':requestHeaders.pairs,
'queryString': queryString,
'headersSize':requestHeaders.size,
'bodySize':object.requestMessage.request.headers['Content-Length'] || -1,
},
'response': {
'status': object.responseMessage.response.status,
'statusText':object.responseMessage.response.statusText,
'httpVersion': protocol,
'cookies': [], // TODO
'headers':responseHeaders.pairs,
'redirectURL': redirectUrl,
'headersSize':responseHeaders.size,
'bodySize': bodySize,
'_transferSize':object.encodedResponseLength,
'content': {
'size':object.responseLength,
'mimeType':object.responseMessage.response.mimeType,
'compression': compression,
'text':object.responseBody,
'encoding':object.responseBodyIsBase64 ? 'base64' : undefined,
}
}
........
}
}
5.从HAR文件中提取需要展示的性能参数
functionGetOverViews(har) {
var getreqstime = function(har) {
var timess = 0;
for (var i = 0; i
timess = timess +har.entries[i].time;
return timess;
};
}
return {
'overview': {
'countoftime': getreqstime(har),
},
'entries': har.entries
};
}
例如通过统计har中所有entries的时间总和来获取当前页面的加载总时间,并将该结果(getreqstime(har))赋值到'contoftime'对象中,前端页面通过调用countoftime即可展示对应的数据。
6.结果展示
总结
本文通过对远程调试协议的应用,介绍了一种简便获取H5页面性能测试数据的解决方案。通过这种方式,测试人员不需要使用第三方工具对H5页面进行调试,而是在建立移动端和PC连接后,通过刷新页面直接可获取性能参数报告,对测试效率的提升带来了极大帮助。目前,为了进一步满足测试的需求,该方案还在精细化调整中,读者有什么建议或意见欢迎留言提出。