公众号旧文

一个链接,为什么能打开微信展示二维码?

作者:胖子阅读 —

今天,我遇到一种链接。

把它复制到手机浏览器里访问,页面先显示“正在跳转到微信”,紧接着,手机弹出提示:

在“微信”中打开此页?

点击“打开”,微信启动,里面出现一个小程序。

小程序展示了一张二维码图片,长按就能识别加微信好友。

看起来只是点了一个链接,背后却经历了几次交接。

我和 Codex 检查了这条链接返回的网页、JavaScript 和后台接口,看到了它究竟怎么工作。

本文中的推广域名、链路编号、小程序 AppID 和访问标识均已替换或打码。

代码仅用于解释,不能直接访问原推广内容。

一、你点击的,还是普通网页

入口链接长得像这样:

https://go.example.com/?code=******&ad_platform=xiaohongshu

其中 go.example.com 是用于说明的示例域名。

这个地址以 https:// 开头,所以浏览器首先按照普通网页处理:

连接服务器,发送请求,获取内容。

我们检查到,这个入口实际返回了:

HTTP/1.1 200 OK

Content-Type: text/html; charset=UTF-8

它返回的是 HTML 网页,不是图片,也不是服务器直接返回的 302 重定向。

网页加载后,又加载了 JavaScript 脚本。

后续的查询、界面展示和跳转,主要由这些脚本完成。

二、同一个网页,为什么能展示不同人的二维码?

关键在入口链接里的 code。

可以把它理解成一张“取件凭条”:

网页拿着这个编号,去后台查询对应的推广配置。

我们看到,脚本会向后台的一个接口发送请求:

GET /api/jump/getScheme

请求中包含:

code=******

ad_platform=xiaohongshu

visit_url=当前访问地址

浏览器中的代码还会附加一个随机生成的设备标识。

这里,code 用于定位这条推广链路;ad_platform=xiaohongshu 是渠道标记。

从命名看,它用于表明这条链接面向小🍠渠道,但它是否参与其他策略,需要更多后台信息才能确定。

后台找到配置后,把页面布局和跳转目标一起返回。

所以,不需要每个人都单独写一个网页。

相同的程序读取不同编号,就可以呈现不同内容。

三、真正打开微信的,是后台返回的另一条链接

接口响应中,我们发现几个关键字段:

{

  ”jump_type”: ”miniapp_qrcode”,

  ”jump_method”: ”1”,

  ”open_type”: ”iframe”,

  ”fallback_url”: ””

}

其中还有一个最关键的字段:jump_url。

它的实际结构是下面这样,识别信息已打码:

weixin://dl/business/?appid=wx****************&path=pages/view/index&query=code%3D******%26unique_code%3D******

这一次,开头变成了:

weixin://

它不再是让浏览器联网获取网页的 HTTPS 地址,而是一条交给微信处理的应用跳转指令。

后面的参数进一步说明了目的地:

参数 作用
appid 指定打开哪个小程序
path 指定小程序里的哪个页面
query 把业务参数传给这个页面

query 里出现的 %3D、%26 是 URL 编码。

解码以后,分别是等号和连接参数用的 &。

这一段解码后的结构是:

code=******&unique_code=******

两次接口请求返回了不同的 unique_code。

它很可能与访问追踪有关,但仅凭公开响应,不能确定它在后台的全部用途。

到这里,关键已经明确:

入口网页拿到了一条“打开指定微信小程序页面”的指令。

四、网页怎么把这条指令交出去?

拿到 jump_url 后,脚本会根据配置选择打开方式。

这条链路配置的是 iframe,代码依次做了几次尝试:

  1. 立即创建一个隐藏的 iframe,把它的地址设置为微信跳转链接。
  2. 约 100 毫秒后,创建一个隐藏的链接元素,调用它的 click()。
  3. 约 1 秒后,再尝试把当前页面地址设置为微信跳转链接。

这些都是网页发起导航请求的方式。

它们不意味着网页获得了任意启动软件的权限,也不保证每次都能成功。

浏览器和来源 App 仍然可以限制或拦截这些请求。

在这次手机实测里,Safari 接受了外部应用跳转请求,并弹出:

在“微信”中打开此页?

图片

这个确认框属于浏览器界面。

它与背景里的“正在跳转到微信”文案不同:

后者只是网页自己画出来的内容。

点击“打开”后,请求才交给微信继续处理。

五、微信打开以后,为什么直接出现那张二维码?

因为传过去的指令已经指定了小程序和页面,还带着业务参数。

微信解析跳转信息,进入相应页面,小程序随后展示对应的二维码内容。

这里要区分两件事:

  • 已经确认的行为: 手机进入了小程序,并展示了预先上传的二维码图片。
  • 尚未直接检查的实现: 小程序内部怎样查询图片、图片最终存在哪台服务器,以及是否经过其他中转。

常见做法是让一个小程序承接许多条推广链路:

进入相同页面,传入不同编号,再读取相应配置。

这样就能服务不同用户,而不需要为每张二维码开发一个小程序。

图片出现以后,用户长按识别,是流程里的下一步。

调起小程序本身,不等于自动识别二维码,更不等于自动加微信好友。

六、为什么不直接打开图片?

图片当然可以直接打开。

问题在于:

你在 Safari 里打开一个普通图片地址,通常会由 Safari 显示图片。

它不会因为图片中有微信二维码,就自动把图片交给微信。

这套方案解决的,是两个连续的问题:

  1. 怎样从微信外部进入微信?
  2. 进入微信以后,怎样呈现指定内容?

在我们分析的案例中,第一个问题由小程序 Scheme 解决,第二个问题由小程序页面解决。

所以,小程序并不是展示二维码的唯一方式,却是这条链路实际采用的承接方式。

如果图片链接本来就在微信聊天里,用户点开再长按识别,就不一定需要小程序,但那是另一个使用场景。

七、整套流程,是几次明确的交接

用户访问普通 HTTPS 链接

          ↓

服务器返回网页,浏览器执行脚本

          ↓

网页携带链路编号,查询后台配置

          ↓

后台返回微信小程序 Scheme

          ↓

网页触发 Scheme,浏览器询问是否打开微信

          ↓

用户确认,微信打开指定小程序页面

          ↓

小程序展示二维码,用户长按识别

从用户眼里看,这是“一个链接打开微信,再出现一张图片”。

从实际实现看,网页、后台、浏览器、系统和微信,各自接手了其中一段工作。

真正把整条链路接起来的,是那条带有小程序身份、页面路径和业务参数的跳转指令。