User Agent 趣事谈

swift 发布于 2017年11月20日
UA 是什么

相信大多数同学都会 UA 已经比较了解了。但在开头还是简短的介绍一下 UA 的基本概念。 我们访问任何一个网站,比如 google.com,你使用的浏览器都会在 HTTP 请求头中附加一个 User Agent 字段,这时我用 Mac 上面的 Chrome 浏览器访问时所发送的请求详细内容:

其中有一个 user-agent 请求头:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36

这个就是我们浏览器发出的 UA 了,对于 Google 网站,当它接受到带有这个 UA 的请求,它就会知道,这个请求来自于一个桌面版本的浏览器,因为 UA 中的 (Macintosh; Intel Mac OS X 10_11_4) 字段已经表明了。 这时 Google 就会给我们的浏览器发回一个桌面版的 Google 网站界面。

同样,如果你这时候用 iPhone 上面的 Safari 请求 Google 网站,那么这时你发出的 UA 大概就会是这样:

Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13C75 Safari/601.1

这个 UA 也表明了我们的这个请求是来自 iPhone,那么 Google 得到这个 UA 后就会根据它的规则,发回给我们一个手机版的网站界面。

这也是现在的网站用于给不同的客户端提供不同界面的通用方法了。

UA 解析

说完了 UA 的基本概念,那么接下来问题就来了,为什么每个 UA 都是这么一大长串东西呢,每一部分都起什么作用呢,它的规则又是什么?

这就要从 IETF 标准说起了。关于 UA 的完整定义可以参看这个 IETF 标准文档 http://tools.ietf.org/html/rfc7231#section-5.5.3

我来帮大家简单分析一下,这个文档中定义了 UA 的构建规则:

User-Agent = product *( RWS ( product / comment ) )

初步一看是不是有点不知所云的感觉~,这里面用的是一种规则语法,product 代表的是软件产品名称,然后 product 本身还包含了子规则:

product         = token ["/" product-version]
product-version = token

这里面 token 代表任意的标识内容,一对中括号表示可选内容,它可以不出现,但如果出现就必须是一个斜杠 / 加上一个 product-version 的形式。

product-version 本身呢,也是一个 token。

咱们就来看一个例子,比如:

Mozilla/5.0

这就是一个 product。 它首先包含了一个 token - Mozilla, 随后有加上了一个可选的斜杠跟随一个 product-version - /5.0

再回看一下我们之前提到的 UA 字符串,是不是从中就找到了很多匹配内容呢,比如: Mozilla/5.0,Safari/537.36, Chrome/50.0.2661.102。 这些其实都符合 product 的规则。

而且根据 product 的定义,后面的版本号也是可以省略的,也就是说这样的标识 MozillaSafari 也是符合这个定义的。

product 规则说完之后,就是后面这串东西了 *( RWS ( product / comment ) ), 我们继续一一分解。

首先 *(), 也就是星号加上一对括号,这个规则标识里面的内容可以出现 0 次或多次, 有正则表达式经验的同学应该就比较熟悉了。

再看看里面的内容, 首先是一个 RWS,其实就是空格。这里面开头至少有一个空格,然后就是一个二选一表达式 ( product / comment ), 它的意思是可以出现一个 product 或者一个 commentproduct 规则咱们上面已经介绍过了。 再来看看 comment 规则。

comment = "(" *( ctext / quoted-pair / comment ) ")"

这个咱们就不展开了,简单来说 comment 规则就是一对圆括号,然后里面写上一些相应的内容。对应到我们实例中,其实就是这种啦

(Macintosh; Intel Mac OS X 10_11_4)

以上就是 UA 格式的完整定义了。 那么看似复杂的 UA,经过这么一番梳理后, 是不是也变得简单了呢。比如我们在开始时提到的 Chrome 发出的 UA:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36

其实转换成规则格式后就是这样 product comment product comment product product。 UA 的每一个分段中,要么是 product,或者是 comment。 其实就这两种。

UA 趣事

UA 中也有一些有意思的事情,比如可能大家会发现,大多数浏览器发出的 UA,都会以 Mozilla 开头。实际上只是因为一个历史原因。在早期的浏览器中, Mozilla 会被很多 Web 站点认为是比较现代化的浏览器,这些站点会针对 Mozilla 标准的浏览器提供更高级的特性,比如 iframe 标签。 而其他浏览器会它们被认为是比较老的,只会对它们返回相对简单的 HTML 界面。

而浏览器发展到今天,其实现在几乎所有的浏览器内核都已经支持这些高级特性了。但鉴于这个历史遗留原因,当前的大多数浏览器都在它们所发送的 UA 的开头中带上了 Mozilla 标识。 Wikipedia 上关于 User Agent 的页面中对这个有更详细的说明,大家有兴趣也可以了解一下,还是挺有意思的。

https://en.wikipedia.org/wiki/User_agent

还有一篇关于浏览器大战的文章,也详细介绍了我们使用的浏览器整个发展历程。最初的浏览器如何从连 CSS 和 JavaScript 都不支持的状态发展到这个水平,里面有非常详细的介绍。值得看一看。

https://en.wikipedia.org/wiki/Browser_wars


如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。
关注微信公众号
发现更多精彩
swift-cafe