你的位置:首页 > Java教程

[Java教程]高程第9章 客户端检测

9.1 能力检测

最常用也最为人们广泛接受的是客户端检测形式是能力检测(又称特性检测).能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力.

检测时,先检测最常用的特性可以保证代码的最优化,因为在多数情况下都可以避免测试多个条件.

必须测试实际要用到的特性.一个特性存在,不一定意味着另一个特性也存在.

9.1.1 更可靠的能力检测

有时只检测方法存在还不行,更好的的方式是检测是不是一个函数.

在可能的情况下,要尽量使用typeof进行能力检测.

在IE8及之前的版本中,用typeof 检测document.createElement()时不是返回true,而是false,因为在IE8及之前它返回的是"object",而不是"function".DOM对象是宿主对象,IE及更早版本中的宿主对象是通过COM而非JScript实现的.IE9及之后,返回"function".

目前使用isHostMethod()方法还是比较可靠的,不过并不能保证百分之百永远可靠.

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

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

9.2 怪癖检测

与能力检测类似,怪癖检测的目标是识别浏览器的特殊行为.

但与能力检测确认浏览器支持什么能力不同,怪癖检测是想要知道浏览器存在什么缺陷("怪癖"也就是bug).

例如,IE8及更早版本中存在一个bug,即如果某个实例属性与[[Enumerable]]标记为false的某个原型属性同名,那么该实例属性将不会出现在for-in循环当中.

另一个经常需要检测的"怪癖"是safari3以前版本会枚举被隐藏的属性.

9.3 用户代理检测

用户代理检测通过检测用户代理字符串来确定实际使用的浏览器.在每一次HTTP请求过程中,用户代理字符串是作为响应首部发送的,而且该字符串可以通过Javascript的navigator.userAgent属性访问.

以下是完整的用户代理字符串检测脚本,包括检测呈现引擎,平台,window操作系统,移动设备和游戏系统.

var client=function(){  //呈现引擎  var engine={    ie:0,    gecko:0,    webkit:0,    khtml:0,    opera:0,    //完整的版本号    ver:null  };  //浏览器  var browser={    //主要浏览器    ie:0,    firefox:0,    safari:0,    konq:0,    opera:0,    chrome:0,    //具体的版本号    ver:null  };  //平台,设备和操作系统  var system={    win:false,    mac:false,    x11:false,    //移动设备    iphone:false,    ipod:false,    ipad:false,    ios:false,    android:false,    nokiaN:false,    winMobile:false,    //游戏系统    wii:false,    ps:false  };  //检测呈现引擎和浏览器  var ua=navigator.userAgent;  if(window.opera){    engine.ver=browser.ver=window.opera.version();    engine.opera=browser.opera=parseFloat(engine.ver);  }else if(/AppleWebKit\/(\S+)/.test(us)){    engine.ver=RegExp("$1");    engine.webkit=parseFloat(engine.ver);    //确定是chrome还是safari    if(/chrome\/(\S+)/.test(us)){      browser.ver=RegExp["$1"];      browser.chrome=parseFloat(browser.ver);    }else if(/Version\/(\S+)/.test(ua)){      browser.ver=RegExp["$1"];      browser.safari=parseFloat(browser.ver);    }else{      //近似地确定版本号      var safariVersion=1;      if(engine.webkit<100){        safariVersion=1;      }else if(engine.webkit<312){        safariVersion=1.2;      }else if(engine.webkit<412){        safariVersion=1.3;      }else{        safariVersion=2;      }      browser.safari=browser.ver=safariVersion;    }  }else if(/KHTML\/(\S+)/.test(ua)||/Konqueror\/([^;]+)/.test(ua)){    engine.ver=browser.ver=RegExp["$1"];    engine.khtml=browser.konq=parseFloat(engine.ver);  }else if(/rv:([^\)]+)\)Gecko\/\d{8}/.test(ua)){    engine.ver=RegExp["$1"];    engine.gecko=parseFloat(engine.ver);    //确定是不是Firefox    if(/Firefox\/(\S+)/.test(ua)){      browser.ver=RegExp["$1"];      browser.firefox=parseFloat(browser.ver);    }  }else if(/MSIE([^;]+)/.test(ua)){    engine.ver=browser.ver=RegExp["$1"];    engine.ie=browser.ie=parseFloat(engine.ver);  }  //检测浏览器  browser.ie=engine.ie;  browser.opera=engine.opera;  //检测平台  var p=navigator.platform;  system.win=p.indexOf("Win")==0;  system.mac=p.indexOf("Mac")==0;  system.x11=(p=="X11")||(p.indexOf("Linux")==0);  //检测Windows操作系统  if(system.win){    if(/Win(?:dows)?([^do]{2})\s?(\d+)?/.test(ua)){      if(RegExp["$1"]=="NT"){        switch(RegExp["$2"]){          case "5.0":            system.win="2000";            break;          case "5.1":            system.win="XP";            break;          case "6.0":            system.win="Vista";            break;          case "6.1":            system.win="7";            break;          default:            system.win="NT";            break;        }      }else if(RegExp["$1"]=="9x"){        system.win="ME";      }else{        system.win=RegExp["$1"];      }    }  }  //移动调协  system.iphone=ua.indexOf("iphone")>-1;  system.ipod=ua.indexOf("iPod")>-1;  system.ipad=ua.indexOf("iPad")>-1;  system.nokiaN=ua.indexOf("NokiaN")>-1;  //window mobile  if(system.win=="CE"){    system.winMobile==system.win;  }else if(system.win=="Ph"){    if(/Windows Phone OS (\d+.\d+)/.test(ua)){      system.win="Phone";      system.winMobile=parseFloat(RegExp["$1"]);    }  }  //检测ios版本  if(system.mac&&ua.indexOf("mobile")>-1){    if(/CPU(?:iPhone)?OS(\d+_\d+)/.test(ua)){      system.ios=parseFloat(RegExp.$1.replace("_","."));    }else{      system.ios=2;//不能真正检测出来,所以只能猜测    }  }  //检测Android版本  if(/Android(\d+\.\d+)/.test(ua)){    system.android=parseFloat(RegExp.$1);  }  //游戏系统  system.wii=ua.indexOf("Wii")>-1;  system.ps=/playstation/i.test(ua);  //返回这些对象  return {    engine:engine,    browser:browser,    system:system  };}();

 

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

不能直接准确地使用能力检测或怪癖检测.

同一款浏览器在不同平台下具备不同的能力.这时候,可能就有必要确定浏览器位于哪个平台下.

为了跟踪分析等目的需要知道确切的浏览器.

9.4 小结

能力检测:在编写代码之前先检测特定浏览器的能力.例如,脚本在调用某个函数之前,可能要先检测该函数是否存在.能力检测无法精确地检测特定的浏览器和版本.

怪癖检测:怪癖实际上是浏览器实现中存在的bug,例如早期WebKit中就存在一个怪癖,即它会在for-in循环中返回被隐藏的属性.怪癖检测通常涉及到运行一小段代码,然后确定浏览器是否存在某个怪癖.由于怪癖检测与能力检测相比效率更低,因此应该只在某个怪癖会干扰脚本运行的情况下使用.怪癖检测无法精确地检测特定的浏览器和版本.

用户代理检测:通过检测用户代理字符串来识别浏览器.用户代理字符串中包含大量与浏览器有关的信息,包括浏览器,平台,操作系统及浏览器版本.

在决定使用哪种客户端检测方法时,一般应优先考虑使用能力检测.怪癖检测是确定应该如何处理代码的第二选择.而用户代理检测则是客户端检测的最后一种方案,因为这种方法对用户代理字符串具有很强的依赖性.