浏览器环境相关检测技术介绍
本文主要介绍以下几项的检测方法:
1. Javascript版本信息
2. Cookie是否开启
3. 用户的屏幕分辨率
4. Flash版本号以及浏览器是否开启了Flash拦截功能
5. 浏览器字体大小是否正常(某些浏览器缩放后会导致页面布局混乱)
6. 浏览器的Ajax功能是否正常,包括Get方式和Post方式
7. 浏览器的图片浏览功能是否正常
8. 用户的网络速度
通过对以上几个问题的检测,开发人员能够比较全面的了解目标浏览器的整体环境。
一、Javascript版本检测
对于Javascript版本的检测似乎显得不是那么必要,因为通常都可以根据浏览器的版本找到对应关系,不过作为浏览器环境的一部分,还是把该功能加了进来,具体的实现原理:在页面中嵌入各个版本的script标签,并在每个标签中都给同一个全局变量赋值,最后根据变量的值得到版本号
<script language="javascript1.0"> JS_VERSION=('1.0'); </script> <script language="javascript1.1"> JS_VERSION=('1.1'); </script> <script language="javascript1.2"> JS_VERSION=('1.2'); </script> <script language="javascriptN"> JS_VERSION=('1.3'); </script> <script type="text/javascript"> window.onload = function(){ if( typeof JS_VERSION != 'undefined' ) document.getElementById('test').innerHTML = JS_VERSION; } </script>
根据W3C规范,script的language属性已经被废弃了,不过经测试该属性的兼容性较好,并能得到比较准确的结果。如果使用type=”text/javascriptN”则在很多浏览器下得不到正确的版本。
另外,javascript版本值可以参考如下表格
Version | Release date | Equivalent to | Netscape Navigator | Mozilla Firefox | Internet Explorer | Opera | Safari | Google Chrome |
---|---|---|---|---|---|---|---|---|
1.0 | March 1996 | 2.0 | 3.0 | |||||
1.1 | August 1996 | 3.0 | ||||||
1.2 | June 1997 | 4.0-4.05 | ||||||
1.3 | October 1998 | ECMA-262 1st edition / ECMA-262 2nd edition | 4.06-4.7x | 4.0 | ||||
1.4 | Netscape Server | |||||||
1.5 | November 2000 | ECMA-262 3rd edition | 6.0 | 1.0 | 5.5 (JScript 5.5), 6 (JScript 5.6), 7 (JScript 5.7), 8 (JScript 6) | 6.0, 7.0, 8.0, 9.0, 10.0 | ||
1.6 | November 2005 | 1.5 + Array extras + Array and String generics + E4X | 1.5 | 3.0, 3.1 | ||||
1.7 | October 2006 | 1.6 + Pythonic generators + Iterators + let | 2.0 | 3.2, 4.0 | 1.0 | |||
1.8 | June 2008 | 1.7 + Generator expressions + Expression closures | 3.0 | |||||
1.8.1 | 1.8 + Native JSON support + Minor Updates | 3.5 | ||||||
1.8.2 | 1.8.1 + Minor updates | 3.6 | ||||||
1.9 | 1.8.1 + ECMAScript 5 Compliance | 4 |
相关参考:
https://www.w3.org/TR/REC-html40/interact/scripts/ W3C关于script标签的描述
https://en.wikipedia.org/wiki/JavaScript#Versions 维基百科关于JavaScript中的版本描述
https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/JavaScript_Overview JavaScript Versions and ECMAScript Editions
https://hi.baidu.com/jiaozhenqing/blog/item/d8f026380392f22cb9998fc7/ JavaScript版本一览
二、检测Cookie是否开启
先获取window.navigator[‘cookieEnabled’]的值,如果该值非undefined的话则直接使用该值即可判断(经测试IE7、Firefox3.5、Safari4、Opera10均能支持)。如果为undefined(即不支持该属性)则使用如下的方式:尝试向Cookie中写入数据(为避免浪费设置1分钟的有效期),写入后检测document.cookie中是否存在刚才写入的数据,如果有则cookie有效否则cookie无效
var cookie = document.cookie; var cookieEnabled = window.navigator['cookieEnabled']; if(typeof cookieEnabled == 'undefined'){ var expireDate = new Date(); expireDate.setTime(expireDate.getTime() + 1000);//Expired after 1 second var time = expireDate*1; var regExp = new RegExp(time + '=' + time); document.cookie = time + '=' + time + ';expires=' + expireDate.toGMTString(); if( regExp.test(document.cookie) ) cookieEnabled = true; else cookieEnabled = false; }
三、Flash版本以及可用性检测
Flash检测包含两方面的内容:
1. Flash是否安装、禁用,Flash版本号
对于Flash的版本检测可以通过在页面中引入AC_OETags.js(包含在Adobe官方的Flash Player Detection Kit中),然后通过调用其中的GetSwfVer方法获得具体的版本号,如果Flash未安装或者被禁用则GetSwfVer方法将会返回-1,否则返回正确的版本号。查看GetSwfVer的实现,与浏览器版本检测如出一辙,也是通过navigator信息得到的,感兴趣的可以直接查看其源码。
2. 如果Flash已经安装是否被拦截
做这一步检查的前提是第一步能够获得正确的版本号。具体的检测方法也很简单,在页面中引入一个自定义的swf文件,在该swf文件中只定义了一个方法checkFlash,并将该方法暴露出来使得JavaScript能够访问到,即ExternalInterface.addCallback(”checkFlash“,checkFlash);在swf加载完成后通过JavaScript访问checkFlash方法,如果存在该方法则说明Flash访问正常,否则Flash可能被拦截了。
以上两步的代码实现大致如下:
HTML代码
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="oCheck" width="0" height="0" codebase="https://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab"> <param name="movie" value="https://co.youa.baidu.com/picture/r/mall/test1/weddiagnose/main/assets/flashcheck.swf" /> <param name="quality" value="high" /> <param name="allowScriptAccess" value="sameDomain" /> <embed id="eCheck" src="https://co.youa.baidu.com/picture/r/mall/test1/weddiagnose/main/assets/flashcheck.swf" quality="high" width="0" height="0" name="flashcheck" align="middle" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="https://www.adobe.com/go/getflashplayer"> </embed> </object>
var version = GetSwfVer(); if( version != -1 ){ var isIE = navigator.appVersion.indexOf("MSIE") != -1; if( isIE )//IE下取Object元素 var swfObj = document.getElementById('oCheck'); else//其他浏览器下取embed元素 var swfObj = document.getElementById('eCheck'); if( !swfObj.checkFlash ) { //被拦截 } else { //未拦截 } } else{ //未安装Flash Player或者Flash Player被禁用 }
四、Ajax功能检测
该功能的检测比较直接,即分别构造Ajax Get和Ajax Post请求,在请求过程中详细的记录Ajax的实例类型(ActiveXObject 或 XMLHTTPRequest)、请求的各个阶段的状态以及最终的请求结果。
五、检测图片是否被禁用
检测图片是否禁用的原理:新建一个Image对象,并监听其onload事件(IE某些版本中无效,需要监听onreadystatechange事件)以及onerror事件。
var img = new Image; //监听onload事件,由于在ie的某些版本中onload事件并不会被触发,因此增加onreadystatechange监听器 img.onload = img.onreadystatechange = function(){ //加载成功说明图片功能是正常的 } //监听onerr事件 img.onerror = function(){ //如果触发了onerror事件,则说明图片功能不正常(在img的src正确的情况下) } img.src = 'xxx';
以上的实现中,对于加载事件的监听并没有什么问题,不过对于onerror事件还是存在比较大的兼容性问题:经测试发现,在IE下禁用图片后并不会触发onerror事件,而在Firefox中禁用图片后则能正常的触发onerror事件,至此的结论是使用onerror来判断图片功能是准确的。取而代之的是使用超时检测来判断,即假定图片在一定时间内仍未能加载成功则视为失败。
var img = new Image; //监听onload事件,由于在ie的某些版本中onload事件并不会被触发,因此增加onreadystatechange监听器 img.onload = img.onreadystatechange = function(){ //加载成功说明图片功能是正常的 } //监听onerr事件 img.onerror = function(){ //如果触发了onerror事件,则说明图片功能不正常(在img的src正确的情况下) } img.src = 'xxx'; var timer = setTimeout(function(){ //如果执行到这里则认为图片功能异常 },TIMEOUT);
六、检测网络速度
实现原理:请求一张已知大小的图片N次,并分别记录每次请求所花费的时间,最后根据图片大小计算出平均的网络速度。这里需要注意的是图片的大小问题,图片如果太小结果会不准确,需要选择一张合适的图片,另外为防止图片被浏览器缓存需要给图片的src添加时间戳。
/* * @param { Integer } times 请求图片的次数 * @callback { Function } callback 图片请求完成后调用的函数 */ function detectNetSpeedWithImage(times,callback){ times = times || 1; //已完成请求 var completedImg = 0, res = [], timer = null, done = false; for( var i = 0; i < times; i++){ (function( index ){ setTimeout(function(){ var img = new Image(); //开关,在某些浏览器(如IE)会响应两次onreadystatechange var loaded = false; //请求开始时间 var tStart = new Date(); img.onload = img.onreadystatechange = function(){ if( loaded ) return; //请求结束时间 var tEnd = new Date(); res.push(tEnd - tStart); //已完成请求加1 completedImg++; loaded = true; //全部请求完成后调用callback if( completedImg == times && callback ){ callback.call(null,res); if( timer ) clearTimeout(timer); } } img.onerror = function(){ if( done ) return; callback([]); done = true; clearTimeout(timer); } img.src = Config.NET_SPEED_DETECT_IMAGE_URL + '?t=' + (new Date())*1; },index * Config.NET_SPEED_DETECT_IMAGE_REQUEST_INTERVAL); })(i); } //超时操作 timer = setTimeout(function(){ if( completedImg != times && !done ){ callback([]); } },Config.NET_SPEED_DETECT_TIMEOUT + times * Config.NET_SPEED_DETECT_IMAGE_REQUEST_INTERVAL); } detectNetSpeedWithImage(Config.NET_SPEED_DETECT_TIMES,function(res){ //失败 if( res.length < 1 ){ _handleError(); } //成功 else{ var time = 0; for( var i = 0,l = res.length; i < l; i++){ time += res[i] / ( l * 1000 ); } //计算速度 var speed = Config.NET_SPEED_DETECT_IMAGE_SIZE / time; //取小数点后两位 speed = speed.toFixed(2); me.isOver = true; } });
七、检测客户端分辨率
直接获取window.screen的width与height即可。
八、检测浏览器字体大小是否正常
在IE6下,当使用px作为单位时,元素(字体大小)无法进行缩放,这在很多情况下都会造成页面混乱。另外,对于目前大多数浏览器,在默认字体设置下,1em恰恰等于16px,于是可以根据这个原理来检测浏览器字体是否正常,具体的方式如下:
1. 创建一个DIV元素1,并设定其高为16px,宽为1px并使用CSS将其定位到可视范围之外(不能通过display或visibility隐藏)
2. 创建另一个DIV元素2,并设置其font-size为medium。在该DIV内部创建一个DIV元素3,并设置其高位1em,宽为1px并使用CSS将其定位到可视范围之外
3. 比较元素1和元素3的高度,如果相等则字体大小正常否则异常
注意,元素3必须包含在元素2中,并且给元素2设置font-size: medium。因为em是一个相对单位,1em的大小相当于其父元素字体的大小,为了使检测不受其他样式影响,将其放在一个字体大小为浏览器默认值的容器中。
//隐藏DIV的CSS var hideCSS = 'position:absolute;left:-2000px;'; //以px为宽度单位的元素 var pxBlock = document.createElement('div'); pxBlock.style.cssText = 'width:16px;height:1px;' + hideCSS; document.body.appendChild(pxBlock); //构建一个字体大小为浏览器默认值的容器 var emBlockWrapper = document.createElement('div'); emBlockWrapper.style.fontSize = 'medium'; //以em为字宽度单位的元素 var emBlock = document.createElement('div'); emBlock.style.cssText = 'width:1em;height:1px;' + hideCSS; emBlockWrapper.appendChild(emBlock); document.body.appendChild(emBlockWrapper); //获得固定和变化的div宽度 var pxBlockWidth = pxBlock.offsetWidth; var emBlockWidth = emBlock.offsetWidth; if(pxBlockWidth == emBlockWidth){ //字体正常 } else{ //字体异常 }
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.