搞定 Facebook 跳转外部浏览器无法下载问题

3,920 阅读6分钟

搞定 Facebook 跳转外部浏览器无法下载问题

问题背景

我们在移动端 facebook 内部浏览器打开一个下载链接的时候,facebook会提示是否使用外部浏览器打开,而当我们选择 chrome 打开的时候,会出现一种情况。 一个空白透明的框框一闪而逝,而我们什么都无法下载,也没办法找到刚刚打开的页面。

当我们进行广告投放或者是一些其他目的的时候,这种情况会严重影响我们的转换率,毕竟 chrome 的用户还是非常多的。那么造成这一现象的原因是什么呢? 本人查询了好多资料,但一直没有在网上找到技术解决方案,最多有一些文章写了如何在 facebook 设置使用外部浏览器打开。

但是作为 FE 的我们,没办法控制用户的手机去进行设置,那只能通过技术手段去解决这一问题。下面是一些探索过程和解决方案

实验方案思路

首先我们猜测一下,为什么会出现问题的情况。经过本人冥思苦想,得到一种猜测方向(未必是正确),但我就这么相信了。(如果不想看实验过程,可直接移到下方解决方案)

原因有二

1.chrome 无法通过 window.open 打开页面, 必须是用户的行为。(这里的用户行为指的是用户的某一行为,比如点击按钮来触发新页面的打开)

2.通过 facebook 打开一个下载链接,可以同化为在 chrome 的当前页面调用了 window.open ,而这并不是用户的主动意愿,失效。

实验过程

  • 在个人页面的 load 过程,使用 window.open 打开一个页面,无效,验证了上面的猜想

  • 在个人下载页面,点击下载按钮生成一个 ifream 下载,希望可以正常下载, 无效

  • 在个人下载页面,点击下载按钮改变 href 下载,希望可以正常下载, 无效

  • 在个人下载页面,点击下载触发 window.open 下载,希望可以正常下载, 无效

  • 在个人下载页面,点击下载触发 改变href 跳转到新的页面,自动触发下载 无效(因为facebook只有在触发下载的时候才会提示是否跳转外部链接,否则还是在内部浏览器)

  • 在个人下载页面,点击下载触发 window.open 跳转到新的页面,自动触发下载 无效(因为facebook只有在触发下载的时候才会提示是否跳转外部链接,否则还是在内部浏览器)

  • 验证window.open 直接在facebook 内置浏览器打开

  • 使用 intent 打开 chrome浏览器, 无效 ( facebook 会拦截intent,而直接转去 google play)

  • 下载各个版本的 chrome 浏览器,检查是否是浏览器版本导致无法打开 (并不是,死马当活马医)

  • 进行 facebook 用户设置,观察是否可以通过设置解决打开问题 (没什么卵用,就算设置成功了也没办法控制用户来设置)

实验了这么些方案,都没有办法解决问题,但帮助我们发现了新的问题

  • facebook 内部规则除下载行为外,其他跳转都会在内部浏览器进行

  • facebook 使用 intent 跳转,会进行拦截,只会跳转 gp

根据发现的 facebook 规则,突然灵光一闪,既然 facebook 只会根据下载行为触发跳转外部浏览器,是否可以模拟下载行为来使之跳转到外部浏览器,然后再在外部浏览器进行下载操作?(感觉希望在向我们招手)

那么接下来的实验变成分析,facebook 识别下载行为的方式是什么?(继续实验)

猜想: 是通过下载地址的后缀来判断是下载行为么?比如 .apk 神马的

  • 在 facebook 打开下载页面后,断开网络,点击下载链接,如果成功调起打开外部浏览器,证明是通过下载链接地址来进行判断的。--- 没有反应 (Orz ,果然太天真了)

  • 了解到下载行为的 headers 里包含一个属性 content-disposition ,那么将下载地址改成一个返回 content-disposition = atachment 的动态页面,是否可以触发下载? --- 成功! 果然触发了 facebook 弹出外部浏览器的窗口

这种方案可行,那么我们就有了一个思路:

通过判断浏览器来进行下载行为的区分,当我们判断到是使用 facebook 内置浏览器的时候,我们将下载按钮做一个欺骗,让他以为是一个下载动作,而我们打开 chrome 的时候,页面不再是一个下载动作,而是一个落地页,接下来我们在这个落地页做什么操作,都不会被拦截了 

解决方案

当用户使用 facebook 浏览器打开官网时,将下载按钮 href 修改为打开其他页面,将此页面返回添加 headers 的content-disposition : atachment 属性,使之作为下载页面。而当使用 chrome 浏览器打开时,作为承载页打开并进行自动下载

解决方案就这么简单!(其实到这里就结束了)

后续问题

不过我们的具体情况后续还面临了一些问题,如果有相同情况的小伙伴,也可以参考一下。

首先因为我们的页面是通过 AWS 的 CDN 进行缓存的处理,其次我们的页面是在 通过 nginx 进行回传,再到 nodejs 进行服务端渲染,所以会导致一个问题:

在服务端渲染的时候,由于此时还没到客户端,我们无法获取到用户的 useragent ,这样我们就没法判断用户来源的浏览器到底是什么。(因为我们想直接通过 chrome 浏览器访问的朋友可以直接进行下载,不用又跳转那么麻烦)

所以 我们使用了 lambda@edge 这样一个方案,具体怎么使用可以移步我的另一篇文章 serverless使用方案,如果我们不在这里处理,通过 cdn 访问的用户在 nodejs 层获取到的 useragent 就会变成 Amazon CloudFront ,无法获取到真实的ua 。

所以我们可以在 lambda@edge 中将 ua 传到 nginx 层,再通过nginx 返回给 nodejs 层,这样就获取到了客户的真实 UA 。 这样,这一系列问题终于闭环了。

完结!撒花!