用户代理检测

前面的文章介绍的是如何检测浏览器对某一功能的支持情况

但是在实践中我们有些时候免不了需要知道用户到底是用的什么浏览器对我们的站点进行访问

这也是统计用户行为的一部分

用户代理检测这种方式就是用于检测用户访问所使用的浏览器的

那么如何进行检测呢?

我之前的文章,讲JS的navigator对象的时候,其中有个 userAgent 属性

这个属性在每次http请求中都会携带在请求头中,这也是我们常说的用户代理字符串

但是要注意的是,这种客户端检测的优先级应该排在 怪癖检测、能力检测之后

作为一种万不得已的手段

为什么呢?因为这和 电子欺骗 有关

所谓电子欺骗,就是指浏览器通过在用户代理字符串中加入错误、误导信息来影响服务器对用户的判断

为什么浏览器要这样做呢?

这就和web早期的发展有关,在早期的发展过程中,用户代理字符串一开始是统一的

但是到了IE4微软希望占据更大的市场,并且希望体现IE的独立性,所以用户代理字符串中就出现了IE自己的标识

这样做使当时的 Netscape(当时最受欢迎的浏览器)很不爽,所以其合作公司通过在服务端检测用户代理字符串,来区分用户

以此来拒绝IE用户的访问

而IE当然不肯善罢甘休,所以就在用户代理字符串中,在不违反标准的情况下添加了混淆信息

其它浏览器厂商纷纷效仿IE

所以检测用户代理字符串来判断浏览器存在一定的风险,准确性也不高

这种方法也就成为了客户端检测的备选方法

和之前一样,这里还是给出一段检测代码

PS:书中检测的只检测到IE11,然而edge的部分并没有,所以这一部分是我自己测试的,有可能会有些问题

用户代理字符串检测函数

// 无需参数
// 返回一个包含浏览器信息的对象
function getClient() {
var engine = {
// 保存浏览器引擎
ie: 0,
gecko: 0,
webkit: 0,
khtml: 0,
opera: 0,
ver: null // 具体版本
}; var browser = {
// 浏览器
ie: 0,
firefox: 0,
safari: 0,
konqueror: 0,// 夸克
opera: 0,
chrome: 0,
ver: null // 浏览器版本
}; var system = {
// PC 端
win: false,
mac: false,
xll: false, // linux
// 移动设备
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){// 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);
// 判断谷歌和safari
if(/Edge\/(\S+)/.test(ua)){// Edge 伪装的很好 所以先检测
engine.ver = browser.ver = RegExp["$1"];
engine.webkit = 0;
engine.ie = "Edge";
browser.ie = "Edge";
}else if (/Chrome\/(\S+)/.test(ua)){
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.konqueror = parseFloat(engine.ver);
}else if(/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)){
engine.ver = RegExp["$1"];
engine.gecko = parseFloat(engine.ver); // 识别火狐
if(/Firefox\/(\S+)/.test(ua)){
browser.ver = RegExp["$1"];
browser.firefox = parseFloat(browser.ver);
}
}else if(/MSIE ([^;]+)/.test(ua)||(/Trident\/(\S+)/.test(ua)&&/rv:([^\)]+)\)/.test(ua))){
// 识别IE
engine.ver = browser.ver = RegExp["$1"];
engine.ie = browser.ie = parseFloat(engine.ver);
} // 平台检测
var p = navigator.platform;
system.win = p.indexOf("Win") === 0;
system.mac = p.indexOf("Mac") === 0;
system.xll = (p === "Xll") || (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 = RegExp.$2;
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 Phone
if(system.win ==="CE"){
system.winMobile = system.win;
}else if(system.win === "Ph"){
if(/Windows Phone OS (\d+.\d+)/.test(ua)||/Windows Phone (\d+.\d+)/.test(ua)){
system.win = "windowsPhone";
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; // 具体版本无法测试,默认为2
}
} // 检测安卓版本
if(/Android (\d+\.\d+)/.test(ua)&& !system.winMobile){
system.android = parseFloat(RegExp.$1);
} // 平台检测
system.wii = ua.indexOf("Wii") > -1;
system.ps = /playstation/i.test(ua); return {
engine: engine,
browser: browser,
system: system
};
}

Javascript高级编程学习笔记(34)—— 客户端检测(3)用户代理检测的更多相关文章

  1. Javascript高级编程学习笔记(32)—— 客户端检测(1)能力检测

    能力检测 浏览器厂商虽然在实现公共接口方面投入了大量的精力 但是每种浏览器仍旧存在许多差异 为了让网页能跨浏览器的运行,对浏览器差异做的兼容处理自然无法避免 其中最常用的也就是我们现在所说的能力检测 ...

  2. Javascript高级编程学习笔记(33)—— 客户端检测(2)怪癖检测

    怪癖检测 和能力检测类似,但其目标不同 能力检测的目的是判断浏览器支不支持某种能力 而怪癖检测的目的是判断浏览器是否存在某些缺陷 这种时候需要我们执行一段代码来判断浏览器是否有这样的缺陷 或者说是怪癖 ...

  3. Javascript高级编程学习笔记(98)—— WebGL(4) WebGL上下文(2)

    错误 Javascript与WebGL之间的一个最大区别在于,WebGL的操作一般不会抛出错误 如果希望获取WebGL的错误信息,那么就需要手动调用  gl.getError() 方法 该方法会返回以 ...

  4. Javascript高级编程学习笔记(97)—— WebGL(3) WebGL上下文(1)

    WebGL上下文 在支持WebGL的浏览器中,WebGL的名字为 "experimental-webgl",这是由于 webgl 的规范仍未制定完成 制定完成后名字就会改为简单的 ...

  5. Javascript高级编程学习笔记(75)—— 表单(3)表单字段

    表单字段 表单作为web应用中不可或缺的一部分,当然也是可以使用原生的 DOM 元素来访问的 除了标准的访问方式之外,每个表单都拥有一个 elements 属性,该属性保存着该表单所有 表单元素 的集 ...

  6. Javascript高级编程学习笔记(64)—— 事件(8)键盘与文本事件

    键盘与文本事件 用户在使用键盘时会触发键盘事件 “DOM2级事件”最初规定了键盘事件,但是最后在定稿时又删除了相应内容 所以键盘事件被放入了DOM3级事件的规范中 总的来说有三个键盘事件: keydo ...

  7. Javascript高级编程学习笔记(53)—— DOM2和DOM3(5)遍历

    遍历 “DOM2级遍历和范围” 定义了两个用于辅助完成顺序遍历的DOM结构类型 NodeIterator 和 TreeWalk 上述两种类型可以基于给定起点的DOM结构执行深度优先的遍历操作 对于检测 ...

  8. Javascript高级编程学习笔记(49)—— DOM2和DOM3(1)DOM变化

    DOM变化 我们知道DOM有许多的版本,其中DOM0和DOM2这两个级别以对事件的纳入标准而为人所知 但是呢,这里不讲事件,在后面会有专门和事件有关的部分作为详细讲解 这里就只讲一下DOM2和DOM3 ...

  9. Javascript高级编程学习笔记(31)—— BOM(5)screen、history对象

    screen对象 screen对象应该是BOM对象中最不常用的对象了 其主要用于提供客户端的显示能力信息 包括浏览器外部显示的信息,和像素的宽高等 这个对象的主要用于检测客户端能力,一般不会影响功能 ...

随机推荐

  1. jQuery on() 方法 为选定已存在元素和未来元素绑定标准事件和自定义事件

    很有必要说说jQuery的on方法,这个方法存在大乾坤大奥秘,主要注意两点: 1.为已存在元素和未来元素(动态添加元素)绑定处理函数. 2.自定义一个非标准的事件并绑定处理函数. 定义和用法 on() ...

  2. select 两层 第二个select需要加别名

    select t.id from (select xxx) t

  3. Git多账号配置,同一电脑多个ssh-key的管理

    为什么有这种需求? 在我们开发过程中,可能会遇到使用同一台机器,既要向公司git服务器提交代码,也要向gitlib或者gitee等 git仓库提交代码,2个仓库设置的用户名信息,不一样,此时需要用到多 ...

  4. 8.Redis内存分配

    8.Redis内存分配8.1 内存消耗8.1.1 内存使用统计8.1.2 内存消耗划分8.1.3 子进程内存消耗8.2 内存管理8.2.1 设置内存上限8.2.2 动态调整内存上限8.2.3 内存回收 ...

  5. 简单的StringBuffer实现

    package com.letv.test.base; import java.util.Arrays; public class StringBuffer { private char[] valu ...

  6. shell脚本实现svn目录同步和提交

    #/bin/bash set -x #提交变更rpm到svn function commit_to_svn() { target_svn_dir=$1 #新增rpm至svn命令 add_to_svn= ...

  7. Python第十七天 抽象类

    from abc import ABCMeta, abstractmethod class A(metaclass=ABCMeta): 称 A 为抽象类 @abstractmethod def tes ...

  8. AHK控制鼠标与键盘

    F4::clicksleep 100MouseGetPos, xpos, ypos x:=xpos+30 click 1877,51sleep 100click 115,51sleep 100clic ...

  9. Qt自定义滚动条(不使用样式表)

    前面使用Qt 样式表实现滚动条,在实际工作中,发现存在一些瑕疵,例如如果在主窗口中绘制背景,则有可能给滚动条染色,还有如果想实现特殊的效果,则必须使用自定义风格,即从QStyle的子类派生出新的类型. ...

  10. ASCII, Unicode, UTF-8, 8进制, 16进制等各种编码学习理解笔记

    字符编码的发展历史 Unicode和UTF-8有何区别? 在这个问题下的于洋的最高票回答中,比较完整地介绍了字符编码的发展历史,为了便于记忆,再次简要概括一番. 一个字节:最初一个字节的标准是混乱的, ...