基于远程调试协议的H5性能测试解决方案

基于远程调试协议的H5性能测试解决方案_第1张图片
立体

前言

为了丰富动态性,移动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:

基于远程调试协议的H5性能测试解决方案_第2张图片

以下是WebSocket Protocol的抓包实例:

基于远程调试协议的H5性能测试解决方案_第3张图片
引用百度百科图片

建立第一次的握手协议后,客户端和服务器之前就开始进行有效的实时通信了。

远程调试协议结构

远程调试协议基于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页面的性能数据。

基于远程调试协议的H5性能测试解决方案_第4张图片
整个操作流程的系统框图

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性能测试解决方案_第5张图片

总结

本文通过对远程调试协议的应用,介绍了一种简便获取H5页面性能测试数据的解决方案。通过这种方式,测试人员不需要使用第三方工具对H5页面进行调试,而是在建立移动端和PC连接后,通过刷新页面直接可获取性能参数报告,对测试效率的提升带来了极大帮助。目前,为了进一步满足测试的需求,该方案还在精细化调整中,读者有什么建议或意见欢迎留言提出。

你可能感兴趣的:(基于远程调试协议的H5性能测试解决方案)