β

iOS QQ 内置浏览器 AJAX 失效的两个原因及解决方法

闪星空间 1503 阅读

今天总算解决了网站的两个 BUG。症状表现都是,用 iOS 上的手机 QQ 内置浏览器,AJAX(通过 jQuery 或是原生 XMLHttpRequest 使用)出现错误。如果不用手机 QQ 内置浏览器,用 iOS 系统自带 Safari,甚至微信内置浏览器,都能正常工作。一个是 GET 请求,另一个是带数据(请求体)的 POST 请求。

后来研究发现,理论上在别的环境下也可能有错,尤其是旧版本的 Safari 等,这是后话了。我们进入正题。

HTTPS 下 GET 请求失败

我的网站大多是强制使用 HTTPS 的,HTTP 请求都会 301 重定向到 HTTPS 页面去。我在 iOS QQ 发了一个网址,点击进去,发现通过 XMLHttpRequest 的 GET 请求失败。通过 status 属性得到状态号是 0,就好像 XMLHttpRequest 没有初始化或连接突然中断一样。换用 jQuery 提交 GET 请求,问题依旧。

在我这里,解决方法是如下的 HTML 代码:

<script>
    if(window.location.protocol == 'http:') window.location.protocol = 'https:';
</script>

实际上是用 JavaScript 代码判断协议,如果发现是 HTTP 协议,就跳转(重定向)到 HTTPS 协议相应的网址。

那我访问的明明是 https:,怎么会成了 http:?仔细观察,我发现自己在 iOS QQ 发的网址没有带协议(或者带 http:// 道理也是一样的),则默认使用 HTTP 协议。尽管可以发现实际访问了 HTTPS 的文档,但浏览器仍然认为是 HTTP 协议:如果用 JS 获取相应的标识,你会得到 HTTP;或者也可以获取相对路径资源的 src,也得到 HTTP;使用 QQ 内置浏览器的复制网址功能,得到的也是 HTTP 的网址。这又是怎么回事?最终我做了个实验发现,是 HSTS 的缘故。推测在 iOS QQ 内置浏览器中,HSTS 并不像其他浏览器那样产生重定向,那么通过 http: 网址进入时,虽然实际访问了 https: 的文档和资源,URL 模式(scheme)却仍然保留着为 http。而 http: 和 https: 的资源不属于同一个源(Origin),就会产生意料之外的跨源问题(参见同源策略),导致 AJAX 请求失败。

带数据 POST 请求失败

我另一个网站遇到的问题是,在 iOS QQ 内置浏览器上,POST 请求失败。相关的程序报告了 xhr.responseText:undefined, type:error 错误,错误码 -1001。于是我自己构造了相关请求,发现把 data 设为 null 时,可以提交;一旦我传上 POST 参数,就会出现前述错误。

这个问题困扰了我好几天。网上有说是因为 XMLHttpRequest 没有初始化,说要定时,延迟发送请求;试过,似乎不起作用。后来我看人家同样的网站内容,却没有问题。那会不会是 HTTPS 的问题呢?可我再找了一个别人的 HTTPS 网站,也是正常的。我就再分析 HTTP 请求头(Request Header)和响应头(Response Header)。虽然我想是没有跨源,但我加上了跨源的相关头也无济于事。突然发现我的响应头名称是小写的,而非一般的单词首字母大写的写法,查询得知这是 SPDY 和 HTTP/2 的规范特性。于是使用“iOS QQ post http2”的关键词查询,看到一篇眼熟的文章:《 谈谈Nginx 的HTTP/2 POST Bug 》。就是它让我解决了这个问题。(后来翻了 Nginx 的错误日志,发现每次 AJAX 请求失败都有 worker process 23415 exited on signal 11 的提示)

文章的问题与我遇到的相似,尽管它提到的受影响范围更大一些,我只专注于观察 iOS QQ 内置浏览器去了。说原因是 Nginx 的实现与 HTTP/2 规范不符,不能正确接收 POST 请求的 DATA 帧,而浏览器可能不会重试,最终导致 POST 请求失败。至于我,早就没在用那旧版本的 Nginx,想了一下发觉是打了 CloudFlare 提供的兼容 SPDY 的补丁,才造成此问题。

我的解决方案就是重新编译安装 Nginx,不要那个鬼补丁了。如果你也遇到相似的问题,还是先看一下自己的 Nginx 版本是不是在 1.10.2 以下,要不要升级版本。新版本已经默认能正确接受 DATA 帧。

以上就是我遇到的问题和解决方法。 造成相关问题的原因可能不止一种,如果你从别处过来却没能解决问题,还请继续探寻,或者在下方留言交流。

作者:闪星空间
“闪闪的星”的独立博客,英文名“Shansing!”。我认为每个人都是一颗闪星,我只是闪星之一。让我们闪闪发光吧,终有一天这里会是闪星空间!