`
琉璃月
  • 浏览: 45031 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

客户端检测

    博客分类:
  • js
阅读更多
客户端检测是javascript开发中最具争议的一个话题。由于浏览器间存在的差别,通常需要根据不同浏览器的能力分别编写不同的代码。有不少客户端检测方法,但下列是最经常实用的。

1)能力检测:在编写代码之前先检测特定浏览器的能力。例如,脚本在调用某个函数之前,可能要先检测该函数是否存在。这种检测方法将开发人员从考虑具体的浏览器类型和版本中解放出来,让他们把注意力集中到相应的能力是否存在上。能力检测无法精确地检测特定的浏览器和版本。

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

3)用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器有关的信息,包括浏览器、平台、操作系统及浏览器版本。用户代理字符串有过一段相当长的发展历史,在此期间,浏览器提供商试图通过在用户代理字符串中添加一些欺骗性信息,欺骗网站相信自己的浏览器是另外一种浏览器。用户代理检测需要特殊的技巧,特别是要注意Opera会隐瞒其用户代理字符串的情况。即便如此,通过用户代理字符串仍然能够检测出浏览器所用的呈现引擎以及所在的平台,包括移动设备和游戏系统。

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

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

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,
          widMobile: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(ua)){
          engine.ver = RegExp["$1"];
          engine.webkit = parseFloat(engine.ver);

          //确定是Chrome还是Safari
          if(/Chrome\/(\S+)/.test(ua)){
               browser.ver = RegExp["$1"];
               browser.chrome = parseFloat(engine.ver);
          }else if(/Vsersion\/(\S+)/.test(ua)){
               browser.ver = RegExp["$1"];
               browser.safari = parseFloat(browser.ver);
          }else{
               //近似地确定版本号
               var safariVersion = 1;
               if(engine.webkit < 100){
                    safariVsersion = 1;
               }else if(engine.webkei < 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(us) || /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+\.\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;

     //windows 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
     };
}();


IE的用户代理字符串:
IE7:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
IE8:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)   (新增的Trident记号是为了让开发人员知道IE8是不是在兼容模式下运行,如果是,则MSIE的版本号会变成7,但Trident及版本号还是会留在用户代码字符串中)
IE9:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)   (如果IE9运行在兼容模式下,字符串中的Mozilla版本号和MSIE版本号会恢复旧的值,但Trident的版本号仍然是5.0)

Firefox的用户代理字符串:
FireFox4:Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox 4.0.1

Safari的用户代理字符串:
Safari3.0:Mozilla/5.0 (Macintosh; U; PPC Mac OS X;en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5

Konqueror的用户代理字符串:
Konqueror3.5:Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) KHTML/3.5.0 (like Gecko)     (Konqueror浏览器只能在Linux中使用)

Chrome的用户代理字符串:
Chrome7:Mozilla/5.0 (Windows; u; Windows NT 5.1;en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7

Opera的用户代理:
Opera8:Opera/8.0 (Windows NT 5.1; U; en)
注:Opera在使用自己的用户代理字符串遇到问题时没有选择通过修改自身的用户代理字符串来迷惑嗅探代码,而是干脆选择通过修改自身的用户代理字符串件自身标识为一个完全不同的浏览器。Opera9以后,出现了两种修改用户代理字符串的方式。一种方式是将自身标识为另外一个浏览器,如Firefox或者IE。在这种方式下,用户代理字符串就如同Firefox或IE的用户代理字符串一样,只不过末尾加了字符串Opera及Opera的版本号。
Opera9.5:(1)Mozilla/5.0 (Windows NT 5.1; U; en; rv:2.0.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50  ----将Opera9.5标识为Firefox2,同时带有Opera版本信息。
(2)Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50   ----将Opera9.5标识为IE6,也包含了Opera版本信息

Opera标识自身的另一种方式,就是把自己装扮成Firefox或IE。在这种隐瞒真实身份的情况下,用户代理字符串实际上与其他浏览器返回的相同——即没有Opera字样,也不包含Opera版本信息。

Opera10.63:Opera/9.80 (Windows NT 6.1; U; en) Presto/2.6.30 Version/10.63

iOS和Android的用户代理字符串:
Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16

Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/Frf91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

除了以上检测方法外,还有一种检测怪癖的方式:如,由于IE8及更早版本将NodeList实现为一个COM对象,而我们不能像使用JScript对象那样使用这种对象,因此用array=Array.propotype.slice.call(nodes,0);这样的代码会导致错误。要想在IE中将NodeList转换为数组,必须手动枚举所有成员。下列代码在所有浏览器中都可以运行:

function convertToArray(nodes){
    var array = null;
    try{
        array=Array.propotype.slice.call(nodes,0);//针对非IE浏览器
    }catch(ex){
        array = new Array();
        for(var i=0,len=nodes.length;i<len;i++){
             array.push(nodes[i]);
        }
    }
    return array;
}


这个convertToArray()函数首先尝试了创建数组的最简单方式。如果导致了错误(说明是在IE8及更早版本中),则通过try-catch块来捕获错误,然后手动创建数组。
分享到:
评论

相关推荐

    js 客户端检测

    在JavaScript的世界里,客户端检测是开发Web应用时不可或缺的一部分,它可以帮助我们了解用户正在使用的设备、浏览器特性,以便实现更好的兼容性和用户体验。这篇博客“js客户端检测”可能深入探讨了如何利用...

    宁盾 Linux客户端检测及终端合规准入方案 (2).docx

    宁盾 Linux客户端检测及终端合规准入方案 (2).docx宁盾 Linux客户端检测及终端合规准入方案 (2).docx宁盾 Linux客户端检测及终端合规准入方案 (2).docx宁盾 Linux客户端检测及终端合规准入方案 (2).docx宁盾 Linux...

    宁盾 Linux客户端检测及终端合规准入方案 (2).pdf

    宁盾 Linux客户端检测及终端合规准入方案 (2).pdf宁盾 Linux客户端检测及终端合规准入方案 (2).pdf宁盾 Linux客户端检测及终端合规准入方案 (2).pdf宁盾 Linux客户端检测及终端合规准入方案 (2).pdf宁盾 Linux客户端...

    客户端检测——用户代理

    客户端检测,可以检测浏览器内核,浏览器类型,移动端类型以及游戏设备

    宁盾 Linux客户端检测及终端合规准入方案.docx

    宁盾 Linux客户端检测及终端合规准入方案.docx宁盾 Linux客户端检测及终端合规准入方案.docx宁盾 Linux客户端检测及终端合规准入方案.docx宁盾 Linux客户端检测及终端合规准入方案.docx宁盾 Linux客户端检测及终端...

    宁盾 Linux客户端检测及终端合规准入方案.pdf

    宁盾 Linux客户端检测及终端合规准入方案.pdf宁盾 Linux客户端检测及终端合规准入方案.pdf宁盾 Linux客户端检测及终端合规准入方案.pdf宁盾 Linux客户端检测及终端合规准入方案.pdf宁盾 Linux客户端检测及终端合规...

    Anjing1993#mypassages#js高程(客户端检测)2016-01-221

    浏览器的种类很多,每个浏览器都有呈现引擎,但是同一款浏览器的不同版本呈现引擎也不一定一样,这就会导致我们同一个页面在不同浏览器下出现差异,这时候客户端检测就成为

    登录远程桌面时遇到“由于客户端检测到一个协议错误(代码0x1104)”

    登录远程桌面时遇到“由于客户端检测到一个协议错误(代码0x1104)”,重新连接N次都还是这个错误提示,最后再重起电脑,还是没用。研究了一下错误终于解决了。

    断网断电心跳检测

    本文将深入探讨“断网断电心跳检测”这一技术主题,以及它与Netty心跳检测的关联。 WebSocket协议允许服务器和客户端之间建立持久连接,允许双向数据传输,极大地简化了实时应用的开发。然而,当网络中断或设备断电...

    yuanyi-au#readingNotes#9. 客户端检测1

    先检测达成目的的最常用特性必须测试实际要用到的特性检测 sort() 方法是否存在并不能确定对象是否支持排序,应该用 typeof() 检测 sort 是否是一

    QT TCP服务端如何判断客户端已断开连接 - 北冥有鱼的博客 - CSDN博客1

    在使用QT进行TCP服务器开发时,一个常见的需求是检测客户端是否已经断开了连接。这篇文章将介绍如何在QT中实现这一功能,特别是在C++环境中。QT提供了丰富的网络编程接口,其中包括`QAbstractSocket`类,该类包含了...

    信息安全技术:绕过客户端检测上传.pptx

    信息安全技术基础

    从客户端检测到有潜在危险的Request.Form值的asp.net代码

    总之,在***开发中处理“从客户端检测到有潜在危险的Request.Form值”时,必须要有强烈的安全意识,不建议关闭请求验证功能,而应该采用合适的方法来处理可能的XSS威胁,确保网站的安全性。对于异常的处理,应当根据...

    zK++:客户端检测模块-开源

    它的开发通常由三个独立并行的项目组成,即: OP Client(一个客户端检测模块,被做成了一个 Hub Guardian); Light Edition(一个友好的模组,灵感来自原始 DC Spirit); 黑色版(客户端的阴暗面,死机进化)

    易语言机器狗检测客户端源码,易语言机器狗检测服务端源码,易语言

    客户端检测到的机器狗信息需要实时更新并呈现给用户,通过刷新超级列表框,用户能够获得最新的检测结果。这不仅提高了用户体验,也使得监控和响应安全事件变得更加迅速和有效。 总体而言,通过分析易语言的机器狗...

    邮局客户端

    邮局检测这一标签暗示了可能存在的测试或诊断工具,如“邮局客户端检测v2.exe”,这可能是一个专门用于检查邮局客户端性能、安全性和兼容性的应用程序。该工具可能包含多种测试场景,例如模拟邮件发送和接收,验证...

    JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)

    综上所述,JavaScript的客户端检测能力对于开发者来说是一个非常有用的技能,它可以帮助开发者针对不同的浏览器和设备提供更好的用户体验。然而,这项技能的掌握需要对各种浏览器和操作系统的UA字符串有深入的了解,...

    java 聊天客户端

    5. 断线重连:客户端检测到网络异常时,自动尝试重新连接服务器。 四、优化方向 1. 引入WebSocket协议:WebSocket提供双向通信,使得服务器能主动推送消息,提高用户体验。 2. 使用分布式架构:当用户量增大时,...

Global site tag (gtag.js) - Google Analytics