微信 - Android 微信里自动调起系统浏览器访问页面
正常情况下,在微信里是无法自动调起系统浏览器访问页面的,但是通过如下所描述的 hack 方式,可以在 Android 微信里自动打开浏览器访问页面。
具体步骤为:
- 在微信里访问页面地址,比如
http://windstone.cc/weixin/auto-launch-browser
。 - 后端或 Nginx 层判断是否是在 Android 微信里访问的,若是则返回如下的核心
response header
;否则正常返回页面内容。 - Android 微信接收到上面的
response header
,会自动调起系统浏览器,并在系统浏览器里再次访问页面地址http://windstone.cc/weixin/auto-launch-browser
,此时后端或 Nginx 层判断出不是在 Android 微信里,则正常返回内容。
HTTP/1.1 206 Partial Content
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Accept-Ranges: bytes
Content-Range: bytes 0-1/1
Content-Disposition: attachment;filename=1579.apk
Content-Length: 0
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Date: Tue, 17 Sep 2019 07:32:12 GMT
Proxy-Connection: keep-alive
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
核心response header
代码片段
这个实现需要后端配合,或者在 Nginx 层里进行处理,要是想简单测试,可以通过 Charles 里的 Breakpoints 设置断点,在页面响应里将response header
修改为上述response header
,即可验证。
进一步优化
在上述的实现里,微信在拉起系统浏览器后,会显示一个白屏的页面,用户需要手动关闭这个页面,体验不好。
可以如下优化:
- 在微信里访问页面地址,比如
http://windstone.cc/weixin/auto-launch-browser
。 - 后端或 Nginx 层正常返回页面内容,页面返回后正常执行、渲染。
- 页面渲染完成后,判断页面所在环境,若是在 Android 微信里,则通过
window.location.href = 'http://windstone.cc/weixin/auto-launch-browser-api'
请求后端接口,接口判断是在 Android 微信里后,返回上述的核心response header
;此时,微信里打开的页面正常显示。 - Android 微信接收到上面的
response header
,会自动调起系统浏览器,并在系统浏览器里再次访问页面地址http://windstone.cc/weixin/auto-launch-browser-api
,此时后端或 Nginx 层判断出不是在 Android 微信里,则通过 302 重定向到http://windstone.cc/weixin/auto-launch-browser
。
此方案还可以通过后端接口控制是否要调起浏览器,防止微信修复了该漏洞后出问题。
核心 response header 的解释
HTTP/1.1 206 Partial Content
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Accept-Ranges: bytes
Content-Range: bytes 0-1/1
Content-Disposition: attachment;filename=1579.apk
Content-Length: 0
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Date: Tue, 17 Sep 2019 07:32:12 GMT
Proxy-Connection: keep-alive
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
206 Partial Content
: 该成功状态响应代码表示请求已成功,并且主体包含所请求的数据区间,该数据区间是在请求的 Range 首部指定的。详见MDN - 206 Partial Contentopen in new windowX-Powered-By: Express
:X-Powered-By
是通用的非标准 HTTP 响应header
(一般以X-
作为前缀的header
都是非标准的)。通常以特殊脚本技术默认包含在响应结构里。需要注意的是,这个头部可以被服务器禁用或修改。有些服务器选择不包含这个头部,甚至提供误导的信息以摆脱黑客,引导其转向一个特殊的技术/版本。因此,这个头部的信息时不足以为信的。更多详细信息,请参考Stack Overflow - What does “x-powered by” mean?open in new window。Accept-Ranges: bytes
: 表示服务器支持Range
请求,且支持的单位是bytes
,也就意味着支持断点续传,可以并行多range
进行下载。若是响应的是Accept-Ranges: none
则表示不支持Range
请求。Content-Range: bytes 0-1/1
: 表示响应的Range
单位、第一个比特的位置、最后一个比特的位置和资源的总长度。此例里,Range
单位是bytes
,第一个比特的位置是0
,最后一个比特的位置是1
,资源的总长度是1
。Content-Disposition: attachment;filename=1579.apk
: 在常规的 HTTP 应答中,Content-Disposition
消息头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。在 HTTP 场景中,第一个参数或者是inline
(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),或者是attachment
(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,将filename
的值预填为下载后的文件名,假如它存在的话)。更多详细信息,请参考MDN - Content-Dispositionopen in new windowETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
: 参考了其他几个第三方跳转服务的response header
,其ETag
的值也是W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
这个固定值。
因此,以上response header
里,最核心的代码应该是Content-Disposition: attachment;filename=1579.apk
。
参考
- 微信跳转外部浏览器打开指定链接源码open in new window
- 第三方跳转服务 - Augpushopen in new window
- 第三方跳转服务 - 月牙跳转open in new window
- 第三方跳转服务 - 忆天网络open in new window