随着浏览器的功能越来越强大,大部分情况下的代码调试都可以通过浏览器自带的一些调试工具来解决。但是对于一些特殊情况,还是无法享受到浏览器强大的调试能力,比如QQ客户端内嵌web的调试(虽然QQ目前可以编译开发者工具,但还是需要安装指定的文件包或工具),异常场景,如嵌入浏览器web和移动端场景。基于这种场景,我们团队推出了nohost下的weinre,并得到了广泛的应用。但是weinre有一定的局限性,只能做console.log和DOM查看等,不能支持断点调试。这里有一些旧文章的描述,见http://www.webryan.net/2013/04/talk-about-remote-debugging-on-mobile-phone/。本文重点介绍在不依赖浏览器控制台能力的情况下,通过JavaScript实现断点调试的能力,为大家解决问题提供另一种思路和方法。首先会给出工具的使用方法,让大家有个感性的认识,然后再讲解具体的实现原理。【测试使用】1、在cmd命令下执行“npminstallbreakpoint-g”(npm安装不再详述,-g为全局安装和注册bin命令)2、在cmd命令下执行“breakpoint”行(会给出帮助,并默认启动test目录:可直接通过URL访问);3、打开chrome和safari等两个现代浏览器,分别打开提示的两个网址。那么,您可以通过三个简单的步骤在浏览器中对其进行测试。这个ui/index.html的操作方法是这样的:是不是很简单:),下面举个实际的例子;【实际使用】【参数说明】用法:breakpoint-dhtdocsDir-rpassbyRule-d指定本地静态目录,这里的调试脚本会被注入到HTML文件的头部。-r指定透传规则,通常用于将CGI请求透传给现网服务器;如果需要透传到指定的服务器,需要在本地的hosts文件中做点;-h当有多个网卡时,可以使用-h来指定某个IP;执行断点后,本地会开启3个端口,80(提供访问服务),8000(控制器),8500(文件改写);【实例】假设我们的域名是:abc.com;本地静态文件(HTML、CSS、JS等)目录为:e:\svn\trunk\htdocs\,那么可以通过“breakpoint-de:\svn\trunk\htdocs”设置所有请求转发到本地目录,例如:http://abc.com/a.html将返回本地目录e:\svn\trunk\htdocs\a.html的内容。但是此时无法在浏览器中直接访问abc.com。需要通过fiddler等工具将abc.com指向本机IP(参考步骤1)。然后访问http://10.64.53.85:8000/ui/index.html打开控制器;访问:http://abc.com/a.html访问资源内容。不难发现,访问内容已经成功到本地,调试脚本自动添加到header中,大功告成。但是往往在调试的时候,我们希望一些文件能够访问到现网资源或者其他服务器的资源。这时候我们可以使用-r参数进行正则化匹配,放开相应的请求。例如:abc.com指向本机IP后,希望abc.com/cgi-bin/下的所有请求都发送到现网。然后只要执行“breakpoint-de:\svn\trunk\htdocs\-rcgi-bin”即可。【原理分析】如何通过JavaScript实现断点调试?断点调试的核心问题是让脚本在某一行代码处暂停执行,所以AleksanderKmetec给出的解决方案是:通过在每行JavaScript代码前添加一个断点函数。断点功能是通过AJAX的同步属性来屏蔽浏览器。那么JavaScript修改前后的情况如下:vara=1;变量b=2;函数测试(){varc='init';c='改变';}Break();vara=1;中断();varb=2;休息();函数测试(){中断();varc='初始化';休息();c='改变';}这样,通过break函数发起一个同步的AJAX请求,判断断点的位置,阻止浏览器执行后面的脚本,真的很聪明。【断点结构图】1.通过浏览器发起网页请求;2.请求通过fiddler等指向我们的重写服务,重写服务根据请求链接进行处理。如果匹配-r的正则规则,则直接转发到现网服务器,否则,请求本地-d目录下的内容。3、透传内容不直接处理,判断其他内容:1、html文件默认会在head***行添加调试脚本的脚本(脚本中包含调试需要的方法),如break();)2.JS文件会加一个break();在每行脚本之前调用函数。4.重写服务返回数据给浏览器。5、浏览器执行JS时,首先会遇到break();然后它会发起一个同步的XHR请求来阻止浏览器的执行。6、如果通过调试服务UI界面设置断点,调试服务会将XHR请求保持在break()中,直到调试服务UI下发新命令(如skip、nextline等)
