Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >九、客户端检测

九、客户端检测

作者头像
jojo
发布于 2022-03-21 12:43:09
发布于 2022-03-21 12:43:09
78400
代码可运行
举报
文章被收录于专栏:jojo的技术小屋jojo的技术小屋
运行总次数:0
代码可运行

作者:汪娇娇

时间:2017年11月26日

检测Web客户端的手段很多,不到万不得已,就不要使用客户端版检测。

一言以蔽之,先设计最通用的方案,然后再使用特定于浏览器的技术增强该方案。

一、能力检测

能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。

  • 先检测达成目的的最常用的特性;
  • 必须测试实际要用到的特性。

错误例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getWindowWidth(){
    if ( document.all ){  //假设是IE,但实际上能支持document.all的浏览器不止IE,比如说Opera
        return document.documentElement.clientWidth;  //错误的用法!
    } else {
        return window.innerWidth;
    }
}

一般检测浏览器下任何对象的某个特性是否存在,要使用下面这个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fucntion isHostMethod( object, property ){
   var t = typeof object[property];
   return t == 'fucntion' || (!!(t == 'object' && object[property])) || t == 'unknown';
}

// 调用
result = isHostMethod(xhr, "open");  //true
result = isHostMethod(xhr, "foo");  //false

二、怪癖检测

怪癖检测的目标识别浏览器的特殊行为。

比如 Safari 3 以前版本会枚举被隐藏的属性,如果浏览器存在这个bug,那么使用 for-in 循环枚举带有自定义的 toString() 方法的对象,就会返回两个toString()的实例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var hasEnumShadowsQuirk = function(){
    var o = { toString: function(){} };
    var count = 0;
    for( var prop in o){
        if( prop == "toString" ){
            count++;
        }
    }
    
    return (count > 1);
}

三、用户代理检测

其优先级排在能力检测和怪癖检测之后。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(function() {
	window.client = {};
	
	//呈现引擎
	var engine = {
		//呈现引擎
		ie: 0,
		gecko: 0,
		webkit: 0,
		khtml: 0,
		opera: 0,
		//具体版本号
		ver: null
	};
	var browser = {
		//浏览器
		ie: 0,
		edge: 0,
		firefox: 0,
		safari: 0,
		konq: 0,
		opera: 0,
		chrome: 0,
		//具体版本号
		ver: null
	};
	//平台、设备和操作系统
	var system = {
		win: false,
		mac: false,
		unix: false,
		//移动设备
		iphone: false,
		ipod: false,
		ipad: false,
		ios: false,
		android: false,
		nokiaN: false,
		winMobile: false,
		//游戏系统
		wii: false, //任天堂
		ps: false //Playstation3
	};
	
	var ua = window.navigator.userAgent;

	//检测Presto内核的Opera浏览器
	if(window.opera) {
		engine.ver = browser.ver = window.opera.version();
		engine.opera = browser.opera = parseFloat(engine.ver);
	}
	//检测WebKit 用代理字符串中的"AppleWebKit"进行检测
	else if(/AppleWebKit\/(\S+)/.test(ua)) {
		engine.ver = RegExp["$1"];
		engine.webkit = parseFloat(engine.ver);
		//确定Microsoft Edge
		if(/Edge\/(\S+)/.test(ua)) {
			browser.ver = RegExp["$1"];
			browser.edge = parseFloat(browser.ver);
		}
		//确定WebKit内核Opera
		else if(/OPR\/(\S+)/.test(ua)) {
			browser.ver = RegExp["$1"];
			browser.opera = parseFloat(browser.ver);
		}
		//确定Chrome
		else if(/Chrome\/(\S+)/.test(ua)) {
			browser.ver = RegExp["$1"];
			browser.chrome = parseFloat(browser.ver);
		}
		//确定Safari
		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.ver = browser.safari = safariVersion;
		}
	}
	//检测KHTML 用于Konqueror3.1及更早版本中不包含KHTML的版本,故而就要使用Konqueror的版本来代替
	else if(/KHTML\/(\S+)/.test(ua) || /Konqueror\/(\S+)/.test(ua)) {
		engine.ver = browser.ver = RegExp["$1"];
		engine.khtml = browser.konq = parseFloat(engine.ver);
		s
	}
	//检测Gecko 其版本号在字符串"rv:"的后面
	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);
		}
	}
	//检测IE
	else if(/MSIE ([^;]+)/.test(ua) || /rv:([^\)]+)\) like Gecko/.test(ua)) {
		engine.ver = browser.ver = RegExp["$1"];
		engine.ie = browser.ie = parseFloat(engine.ver);
	}
	//获取平台或者操作系统信息,可能的值:win32、win64、MacPPC、MacIntel、Xll、Linux i686
	var p = window.navigator.platform;
	//检测平台
	system.win = p.indexOf("Win") == 0;
	system.mac = p.indexOf("Mac") == 0;
	system.unix = (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 "7":
						system.win = "7";
						break;
					case "8":
						system.win = "8";
						break;
					case "8.1":
						system.win = "8.1";
						break;
					case "10.0":
						system.win = "10.0";
						break;
					default:
						system.win = "NT";
						break;
				}
			}
		}
	}
	//移动设备
	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; //不能真正检测出来,所以只能猜测
		}
	}
	//检测安卓版本
	if(/Android (\d+.\d+)/.test(ua)) {
		system.android = parseFloat(RegExp["$1"]);
	}
	//检测游戏系统
	system.wii = ua.indexOf("wii") > -1;
	system.ps = /playstation/i.test(ua);
	
	window.iClient.engine = engine;
	window.iClient.browser = browser;
	window.iClient.system = system;
})();

四、小结

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

1、能力检测:在编写代码之前先检测特定览器的能力。例如,脚本在调用某个函数之前,可能要先检测该函数是否存在。这种检测方法将开发人员从考虑具体的浏览器类型和版本中解放出来,让他们把注意力集中到相应的能力是否存在上。能力检测无法精确地检测特定的浏览器和版本。 2、怪癖检测:怪癖实际上是浏览器实现中存在的bug,例如早期的 Webkit中就存在一个怪癖,即它会在for-in循环中返回被隐藏的属性。怪癖检测通常涉及到运行一小段代码,然后确定浏览器是否存在某个怪癖。由于怪癖检测与能力检测相比效率更低,因此应该只在某个怪癖会干扰脚本运行的情况下使用。怪癖检测无法精确地检测特定的浏览器和版本。 3、用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器有关的信息,包括浏览器、平台、操作系统及浏览器版本。用户代理字符串有过一段相当长的发展历史,在此期间,浏览器提供商试图通过在用户代理字符串中添加一些欺骗性信息,欺骗网站相信自己的浏览器是另外一种浏览器。用户代理检测需要特殊的技巧,特别是要注意 Opera 会隐瞒其用户代理字符串的情况。即便如此,通过用户代理字符串仍然能够检测出浏览器所用的呈现引擎以及所在的平台,包括移动设备和游戏系统。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017/11/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
浏览器探针--JavaScript
HTTP规范(包括1.0和1.1版)明确规定,浏览器应该发送简短的用户代理字符串,指明浏览器的名称和版本号。 RFC 2616 (即HTTP1.1协议规范)是这样描述用户代理字符串的:
奋飛
2019/08/15
1.6K0
《javascript高级程序设计》核心知识总结
浮点数值的最高精度是17位小数,但在进行算术计算时精度远远不如整数。例如 0.1 + 0.2 === 0.300000000000004(大致这个意思,具体多少个零请实际计算) 所以永远不要测试某个特定的浮点数值
徐小夕
2019/10/08
2.4K0
js判断手机端和pc端
navigator对象有一个属性为userAgent,这是一个只读的字符串,声明了浏览器用于HTTP请求的用户代理头的值。所以我们可以通过判断navigator.userAgent里面是否包含某些值来判断。如下为userAgent的打印值。
用户1349575
2022/01/26
8.3K0
模拟mui框架编码
//调用方法 /* 1、tm.os.ios/tm.os.android/tm.os.versions().webKit //表示安卓设备/ios设备/webKit内核 */ var tm = (function(document) { "use strict"; var readyRE = /complete|loaded|interactive/, //complete 可返回浏览器是否已完成对图像的加载。 idSelectorRE = /^#([\w-]+)$/,
White feathe
2021/12/08
1.3K0
JavaScript 高级程序设计(第 4 版)- 客户端检测
分析浏览器 通过解析浏览器返回的用户代理字符串,可以极其准确地推断出下列相关的环境信息:
Cellinlab
2023/05/17
8340
H5与Android&iOS客户端原生APP通信交互实现
最近有个需求,原生 APP 使用 webView 内嵌 H5 页面,APP 未登录状态下打开 H5 页面,在页面中登录,再返回 APP 时要保持登录状态(APP 也要同步登录)。
德顺
2021/01/21
2.7K0
通过Js判断客户端为PC端还是手持设备
Js中获取浏览器信息字符串只要使用navigator.userAgent即可,这样我们再利用indexof来判断版本或其它信息了。
WindCoder
2018/09/20
7.7K0
pc 和 ipad 端网站适配
方法一:设置fontsize 按照iphone 5的适配 1em=10px 适配320
公众号---人生代码
2020/11/11
3K0
100个常用的 JS 代码片段分享,值得你收藏
function cutstr(str, len) { var temp; var icount = 0; var patrn = /[^\x00-\xff]/; var strre = ""; for (var i = 0; i < str.length; i++) { if (icount < len - 1) { temp = str.substr(i, 1); if (patrn.exec(temp) == null) { icount = icount + 1 } else { icount = icount + 2 } strre += temp } else { break } } return strre + "..." }
前端达人
2021/10/08
2.4K0
JavaScript 103 条技能
1、原生JavaScript实现字符串长度截取 function cutstr(str, len) { var temp; var icount = 0; var patrn = /[^\x00-\xff]/; var strre = ""; for (var i = 0; i < str.length; i++) { if (icount < len - 1) { temp = str.substr
guanguans
2018/04/27
8770
JavaScript详细判断浏览器运行环境
看到标题,大家就能想起这个需求在很多项目上都能用到。我们部署在Web服务器上的前端应用,既可以用PC浏览器访问,也可以用手机浏览器访问,再加上现在智能设备的推广,我们甚至能在车载系统、穿戴设备和电视平台上访问。
JowayYoung
2020/04/01
2.3K1
JavaScript详细判断浏览器运行环境
原生态纯JavaScript 100大技巧大收集---你值得拥有(1--50)
1、原生JavaScript实现字符串长度截取 function cutstr(str, len) { var temp; var icount = 0; var patrn = /[^\x00-\xff]/; var strre = ""; for (var i = 0; i < str.length; i++) { if (icount < len - 1) { temp = str
用户1272076
2019/03/26
6320
H5页面判断客户端是iOS或者Android并跳转对应链接唤起APP
每个客户端都会有自己的 UA (userAgent)标识,可以用 JavaScript 获取客户端标识。
德顺
2019/11/12
13.6K0
jQuery来源学习笔记:扩展的实用功能
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/117736.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/05
5830
JavaScript判断浏览器版本的方法
因为业务需求,项目经理让我做一个判断当前浏览器是否是谷歌浏览器,并确定谷歌浏览器版本,不满足谷歌浏览器和版本就显示一个页面提示升级,满足条件就跳转到我们的一个项目,下面先来实现这个:
用户1289394
2021/10/13
1.5K0
BiugleJS
老猫-Leo
2023/12/11
1710
JS-检测浏览器类型及版本
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 </head> 8 9 <body> 10 <script type="text/javascript"> 11 function myBrowser() { 12 var userAgent =
xing.org1^
2018/05/17
2.8K0
分享前端开发常用代码片段
如果你的网页中需要使用大量初始不可见的(例如,悬停的)图像,那么可以预加载这些图像。
前端教程
2018/07/27
1.2K0
分享前端开发常用代码片段
create common utils.js
/* * author:w候人兮猗(ahwgs) * url:https://www.ahwgs.cn * github:https://github.com/ahwgs/common-utils/blob/master/utils * */ /** * 是否是数组 * @param value * @returns {boolean} */ export const isArray = (value) => { return toString.call(value) === '[obje
w候人兮猗
2020/07/01
1.1K0
浏览器User-Agent简史
1)浏览器User-Agent(UA)也叫做用户代理字符串,是一个浏览器发出请求时表明身份的标记。
零云
2023/07/24
5120
浏览器User-Agent简史
相关推荐
浏览器探针--JavaScript
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验