9 客户端检测

本章内容

  • 使用能力检测
  • 用户代理检测的历史
  • 选择检测方式

9.1 能力检测

能力检测的基本模式如下:

if (object.propertyInQuestion) {
  //使用 object.propertyInQuestion
}

举例子,IE 5.0 之前版本不支持document.getElementById()这个 DOM 方法。

function getElement(id) {
  if (document.getElementById) {
    return document.getElementById(id);
  } else if (document.all) {
    return document.all(id);
  } else {
    throw new Error("No way to retrieve element");
  }
}

9.1.1 更可靠的能力检测

能力检测对于想知道某个特性是否会按照适当方式行事(而不仅仅是某个特性存在)非常有用。来看下面的函数,它用来确定一个对象是否支持排序。

//不要这样做!这不是能力检测--只检测了是否存在相应的方法
function isSortable(object) {
  return !! object.sort;
}

更好的方式是检测sort是不是一个函数。

//这样更好,检查 sort 是不是函数
function isSortable(object) {
   return typeof object.sort == "function";
}

9.1.2 能力检测,不是浏览器检测

检测某个或某几个特性并不能够确定浏览器。
实际上,根据浏览器不同将能力组合起来是更可取的方式。如果你知道自己的应用程序需要使用某些特定的浏览器特性,那么最好是一次性检测所有相关特性,而不是分别检测。

在实际开发中,应该将能力检测作为确定下一步解决方案的依据,而不是用它来判断用户使用的是什么浏览器。

9.2 怪癖检测

怪癖检测的目标是识别浏览器的特殊行为。但与能力检测确认浏览器支持什么能力不同,怪癖检测是想要知道浏览器存在什么缺陷。通常需要运行一小段代码,以确定某一特性不能正常工作。

9.3 用户代理检测

第三种,也是争议最大的一种客户端检测技术叫做用户代理检测。用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。在每一次 HTTP 请求过程中,用户代理字符串是作为响应首部发送的,而且该字符串可以通过 JavaScript 的navigator.userAgent属性访问。在服务器端,通过检测用户代理字符串来确定用户使用的浏览器是一种常用而且广为接受的做法。而在客户端,用户代理检测一般被当作一种万不得已才用的做法,其优先级排在能力检测和怪癖检测之后。

9.3.1 用户代理字符串的历史

9.3.2 用户代理字符串检测技术

一般情况下,知道呈现引擎和最低限度的版本就足以决定正确的操作方法了。

  1. 识别呈现引擎
    我们要编写的脚本将主要检测五大呈现引擎:IE、Gecko、WebKit、KHTML 和 Opera。
    检测脚本的基本代码结构如下所示:
var client = function () {
  var engine = {
    //呈现引擎
    ie: 0,
    gecko: 0,
    webkit: 0,
    khtml: 0,
    opera: 0,
    //具体的版本号
    ver: null
  };
  //在此检测呈现引擎、平台和设备
  return {
    engine: engine
  };
}();

在这个对象字面量中,每个呈现引擎都对应着一个属性,属性的值默认为 0。如果检测到了那个呈现引擎,那么就以浮点数值形式将该引擎的版本号写入相应的属性。而呈现引擎的完整版本,则被写入ver属性。作这样的区分可以支持像下面这样编写代码:

if (client.engine.ie) {
  //针对 IE 的代码
} else if (client.engine.gecko > 1.5){
  if (client.engine.ver == "1.8.1") {
    //针对这个版本执行某些操作
  }
}

要正确地识别呈现引擎,关键是检测顺序要正确。为此,第一步就是识别 Opera,因为它的用户代理字符串有可能完全模仿其他浏览器。

if (window.opera) {
  engine.ver = window.opera.version();
  engine.opera = parseFloat(engine.ver);
}

应该放在第二位检测的呈现引擎是 WebKit。因为 WebKit 的用户代理字符串中包含"Gecko""KHTML"这两个子字符串,所以如果首先检测它们,很可能得出错误的结论。
不过,WebKit 的用户代理字符串中的“AppleWebKit”是独一无二的,因此检测这个字符串最合适。下面就是检测该字符串的示例代码:

var ua = navigator.userAgent;
if (window.opera) {
  engine.ver = window.opera.version();
  engine.opera = parseFloat(engine.ver);
} else if (/AppleWebKit\/(\S+)/.test(ua)) {
  engine.ver = RegExp("$1");
  engine.webkit = parseFloat(engine.ver);
}

接下来要测试的呈现引擎是 KHTML。同样,KHTML的用户代理字符串中也包含“Gecko”。KHTML 的版本号与 WebKit 的版本号在用户代理字符串中的格式差不多。因此可使用类似的正则表达式。
在排除了 WebKit 和 KHTML 之后,就可以准确地检测 Gecko 了。
最后一个要检测的就是 IE 了。版本号位于字符串“MSIE”的后面,一个分号的前面。

else if (/MSIE ([^;]+)/.test(ua) {
  engine.ver = RegExp["$1"];
  engine.ie = parseFloat(engine.ver);
}
  1. 识别浏览器
    由于 Chrome 和 Safari 都使用 WebKit 作为呈现引擎,但它们的 JavaScript 引擎不一样。需要进一步识别。
  2. 识别平台
    目前三大主流平台是 Windows、Mac 和 Unix(包括各种 Linux)。
var p = navigator.platform;
system.win = p.indexOf("Win") == 0;
system.mac = p.indexOf("Mac") == 0;
system.xll = (p.indexOf("Xll") == 0 || p.indexOf("Linux") == 0);
  1. 识别 Windows 操作系统
  2. 识别移动设备
  3. 识别游戏系统

9.3.3 完整的代码

9.3.4 使用方法

用户代理检测一般适用于下列情形。

  • 不能直接准确地使用能力检测或怪癖检测。
  • 同一款浏览器在不同平台下具备不同的能力。这时候,可能就有必要确定浏览器位于哪个平台下。

9.4 小结

客户端检测是 JavaScript 开发中最具争议的一个话题。下列方法是最经常使用的。

  • 能力检测:在编写代码之前先检测特定浏览器的能力。
  • 怪癖检测:怪癖实际上是浏览器实现中存在的 bug。
  • 用户代理检测:通过检测用户代理字符串来识别浏览器等信息。
    一般应优先考虑使用能力检测。怪癖检测是确定应该如何处理代码的第二选择。而用户代理检测应是最后一种方案。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容