1.背景
移动互联网发展到今天,由于H5的跨平台、高效率、低成本等优势,我们的前端开发工作内容已不仅仅局限于浏览器端的网页,现在很多应用都已经引入了新的开发模式:Hybrid APP。
Hybrid APP底层依赖于Native提供的容器(UIWebview),上层使用HTML、CSS和JavaScript来开发,这样的方式使得应用更新迭代变得更加敏捷和高效,所以Hybrid APP应用越来越多。但是随之而来的会有很多新问题,比如今天我们要谈到的实际开发中前端如何模拟客户端环境实时调试。
传统的前端开发,在PC端我们可以用浏览器直接打开html页面,实时查看和调试页面,移动端可以借助类似BrowserSync这种实时同步工具来调试,但是在Native下,很多时候我们需要依赖用户的信息或者依赖客户端的一些行为,只能先提测或者上线,让客户端同学给配一个测试或线上入口url,每次更新了代码,都要push代码,然后在客户端内查看效果,这还只是应对新需求未上线的功能,一旦项目上线有bug需要修复,我们没有客户端的真实环境,比如测试环境没有正式环境的某些数据,很难将问题复现出来,也不可能拿线上代码直接去push调试,所以这种方案显然不合理。那么有什么办法能让我们修改完本地代码后,直接重载客户端的Webview,就能实时看到Native中最新效果了呢,下面介绍一种开发模式,满足我们的Hybrid H5开发需求。先来看看一个实际案例:
2.案例描述
前些天测试同学给我提了个bug单,大概是这样的:我们的书城客户端内有一个专题,内容是一些书籍列表,每个书籍都有一个『阅读』按钮,bug现象是“打开的书籍与专题中实际点击的不一致,打开的是该专题下最后一本书。”。看描述猜测原因应该是:点击阅读按钮时候调用的 readbook() 方法,需要传入所选书籍信息作为参数,传参逻辑出现了问题。
因为这个专题模板之前不是我写的,专题模板又兼容了多类专题,代码量庞大,所以熟悉了下代码框架后先基本确认了问题点,果然是这里的readbook() 方法的参数在列表循环数据的时候被覆盖了,这里需要重新兼容一个逻辑处理,修复完毕。但是改别人的代码最担心的就是牵一动百,而且这个专题只有线上正式环境才有,测试环境没有,也不想再去麻烦运营同学给测试环境配一堆数据,所以问题来了,怎么才能在本地客户端环境实时调试H5而不把风险留给正式环境来测呢?先梳理下思路。
3.思路梳理
我们需要搞清楚两个问题:
1.如何本地调取线上环境接口数据,没数据我们无法测试该专题;
2.如何将本地代码实时同步到客户端内访问。
先看第一个问题,我们的js网络协议层的方案大概是这样的,先判断当前url域名是不是线上域,是的话就调正式环境后端服务接口,否则就掉测试环境后端接口,网络协议层一般是不动的,我不能为了测试去修改网络层规则再提测,这也是不合理的,所以解决这个问题的第一步,就是模拟正式域。这里我们的方案思路是使用nginx代理服务器配合修改hosts文件来实现,将正式域名 iyuedu.qq.com 在开发环境中直接指向本地代码,有了这个基础,第二个问题自然想到通过给手机挂代理来实现。
4.安装nginx服务器
首先安装nginx服务器,以下演示以Mac为例,Windows下nginx安装见此。
1.Homebrew安装
Mac下nginx要通过Homebrew来安装(简称brew),brew是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件。
Homebrew的安装非常简单,打开终端复制、粘贴以下命令,回车:
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew安装完毕后,可以在终端输入命令「brew -v」检查以下是否安装成功(若失败,多试几次):
返回了Homebrew 1.2.1版本号,说明brew已经安装成功。
2.nginx安装
接下来继续安装nginx,执行命令:
brew search nginx
brew install nginx
可能由于网络因素,安装的时候花费了很长时间,中间失败了两次,所以这里如果安装不顺畅,请多尝试几次即可。
同样安装完毕后我们可以通过命令「nginx -v」查看nginx是否安装成功:
返回 nginx/1.12.0 版本,搞定。
5.修改ngnix.conf配置
nginx已经安装完毕,但是我们还要通过对nginx的一些配置,让它使我们的线上域名“ iyuedu.qq.com ”在本机中指向本地的代码目录。
打开Finder,前往文件夹 “/usr/local/etc/nginx/” ,然后找到 nginx.conf 文件,打开并进行编辑:
找到 http 下的 server,进行如下配置修改:
server {
listen 80;
server_name iyuedu.qq.com;
set $path '/Users/luping/Desktop/work/git_code/baipai/oppo-webapp-html/WebContent/6_0/';
location / {
root $path;
index index.html index.htm;
autoindex on;
}
}
这里我们使用 80 端口,server_name很好理解,就是我们主机的名称,我们使用线上域名“iyuedu.qq.com”,然后设置一个变量$path来保存本地代码路径,在location中赋值给root。
保存,关闭,其他的地方保持原配置暂不用修改。
注意,这里会有两个坑,后面运行的时候再分析解决。
6.修改hosts文件
hosts文件是一个用于储存计算机网络中各节点信息的计算机文件,我们可以配置ip地址和其对应主机名。
打开Finder,前往文件夹 “/private/etc/hosts” ,找到hosts文件,先复制一份到桌面,然后打开,我们将默认的 “127.0.0.1 localhost” 先注释,再添加一条:
# 127.0.0.1 localhost
127.0.0.1 iyuedu.qq.com
保存后,在粘贴回 “/private/etc/hosts”目录下,这里需要提供下管理员密码,继续即可。至此我们的hosts文件也修改完毕,将本地的ip对应到了我们的想要的正式域名“iyuedu.qq.com”。
7.启动&解决问题
1.启动
终于等到这一刻,是时候看一下修炼成果了,我们需要启动nginx服务,这里先普及下nginx常用的几个命令:
sudo nginx #打开 nginx
nginx -s reload|reopen|stop|quit #重新加载配置|重启|停止|退出 nginx
nginx -t #测试配置是否有语法错误
nginx [-?hvVtq] [-s signal] [-c filename] [-p prefix] [-g directives]
-?,-h : 打开帮助信息
-v : 显示版本信息并退出
-V : 显示版本和配置选项信息,然后退出
-t : 检测配置文件是否有语法错误,然后退出
-q : 在检测配置文件期间屏蔽非错误信息
-s signal : 给一个 nginx 主进程发送信号:stop(停止), quit(退出), reopen(重启), reload(重新加载配置文件)
-p prefix : 设置前缀路径(默认是:/usr/local/Cellar/nginx/1.2.6/)
-c filename : 设置配置文件(默认是:/usr/local/etc/nginx/nginx.conf)
-g directives : 设置配置文件外的全局指令
好了,首先我们启动nginx:
sudo nginx
按照配置,我们把本地的localhost修改为了“iyuedu.qq.com”,然后直接指向了代码目录,所以理论上我们打开浏览器直接访问 “http://iyuedu.qq.com/topicV2.html” 就可以访问到这个专题文件topicV2.html了,试一试:
发现nginx给我们报了个错,提示 “403 Forbidden”,目测是权限问题,nginx不允许查看。看来我们还要再修改一下nginx.conf配置文件,在nginx.conf文件的最顶部加一句
user root owner;
保存,然后在终端重启nginx:
sudo nginx -s reload
在浏览器中再刷新一下:
看样子好像成了,我们几乎达到了目的,本地访问域名“iyuedu.qq.com”但实际访问的是本地的代码,而且显然已经成功的取到了后端线上接口数据,经测试,修改了一下本地代码,浏览器中一刷新,页面会立刻看到更新改动,这不正是我们想要的吗,但是,好像还差那么一点点,对比了下这个专题真正的线上url,是这样的:
http://iyuedu.qq.com/act/6_0/topicV2.html
而我们目前模拟出来的是:
http://iyuedu.qq.com/topicV2.html
对比发现,我们模拟的url缺少了一部分路径 “/act/6_0”,这样的话显然不能进行下面的代理客户端中页面url的工作了,所以我们必须要模拟得一模一样!
好吧,我们继续填坑。
2.解决,location中root和alias
上面我们只是用nginx和hosts来启动了服务和修改了本地ip对应的主机名称为我们的正式域名,那么继续给这个域名配一个虚拟的路径,谁来做呢?当然还是nginx, hosts文件能力有限,只能修改一下主机名称,真正挑大梁的还是nginx。
原来nginx.conf中的location指定文件路径有两种方式:root和alias。
root与alias主要区别在于nginx如何解释location后面的uri,这会使两者分别以不同的方式将请求映射到服务器文件上。
[root]
语法:root path
默认值:root html
配置段:http、server、location、if
[alias]
语法:alias path
配置段:location
root实例:
location ^~ /path/ {
root /www/page/html/;
}
如果一个请求的URI是 /path/a.html 时,web服务器将会返回服务器上的 /www/page/html/path/a.html 的文件。
alias实例:
location ^~ /path/ {
alias /www/page/html/;
}
如果一个请求的URI是 /path/a.html 时,web服务器将会返回服务器上的/www/page/html/a.html的文件。注意这里是 /www/page/html ,因为alias会把location后面配置的路径“/path”丢弃掉,把当前匹配到的目录指向到指定的目录。
知道了这一点,我们要做的就是使用alias修改一下nginx.conf,我们缺少的路径是“/act/6_0/”,所以修改如下:
server {
listen 80;
server_name iyuedu.qq.com;
set $path '/Users/luping/Desktop/work/git_code/baipai/oppo-webapp-html/WebContent/6_0/';
location ^~ /oppo/6_0/ { // *修改下location*
alias $path; // *使用 alias *
index index.html index.htm;
autoindex on;
}
}
保存nginx.conf文件,然后再次重启nginx服务:
sudo nginx -s reload
再次回到浏览器,我们输入线上正式的url:
http://iyuedu.qq.com/act/6_0/topicV2.html?tid=327950&tf=1
刷新,页面正常显示:
但是,这个页面访问的代码到底是不是我们本地的代码呢,试一下便知,我们修改下“阅读”按钮的文案为“test”,保存看看是否及时生效:
没毛病,成了,现在我们已经完全在本地模拟了线上正式域页面的url
,也成功取到了线上接口数据,接下来就是在客户端内实时预览这个页面了。
8.客户端实时预览H5
我们已经在本地启了nginx服务,修改了主机名为线上域名,所以接下来我们只需要让手机和Mac处于同一个局域网内,并且给手机挂上代理,就可以在线上包客户端内访问到我们的本地代码页面了,有了客户端环境,我们就可以更方便地进行调试了,这正是我们想要的。
给手机挂代理,我们需要在电脑上启动一个常用的抓包软件,Mac上我用的是 Charles,Windows下一般是Fiddler,启动后一般默认端口是8888,当然也可以自己修改,这里我们就不修改直接使用默认的端口号8888。
然后再找一下电脑当前的ip,Mac-设置-网络 就可以看到我的是192.168.1.112。
注意,有的公司的内部局域网考虑安全因素设置了比如AP隔离等,导致连接到同一局域网内的设备不能互相通信,当然也不能进行抓包等操作,这种情况下需要我们使用电脑开启网络热点来让移动设备连接,关于Windows和Mac开启热点的方式:
Windows用户看这里
Mac用户看这里
拿出我们的手机,连接到与当前电脑同一个wifi局域网,对该wifi网络进行高级设置-代理,主机名输入我们的电脑IP,端口输入8888,然后确定保存,这时我们的手机就已经挂上代理了。
然后打开app客户端,找到这个专题,点击进去,发现这个页面的“阅读”按钮的文案已经是“test”了,说明我们的客户端由于手机挂上了我们的本地网络代理,url自动指向了本地代码目录。这样,我们的终极目标就达到了,现在客户端环境下,我们已经可以随时调试本地的H5代码了。
9.小结
这只是一个开发模式上的优化方案,虽然略复杂麻烦一些,但是也大大提高了开发的效率和可靠性,也切实为我们解决了一些棘手的问题。由于本人经验和能力有限,文中提到的一些地方如有描述不准确或者错误的地方,欢迎大家指正,也相信还有更加便捷的方法来实现这个需求,先这样吧,88。 [愉快]