javascript 识别客户端唯一性

项目中想统计页面的点击次数、浏览人数等,类似百度统计吧,但是很简单,就很随意的功能。

实现思路打算:
	前端页面,ajax 直接传递一些相关参数,记录到 mysql 中,然后后台分析...

	mysql 字段:
		id
		user_id - 如果用户登录,顺带记录下 uid
		unique_id - 唯一标识
		path - 访问页面路径
		user_agent - 记录用户的完成 user agent
		device - 设备(pc、android、ios等,对 user agent 的解析)
		created_at
		updated_at

功能很简单,但是有个问题,如何识别 "唯一用户",这个并不是基于我们用户登录后,进行统计,没法通过用户的 uid 来判断。

一般认定的唯一用户应该是:只要通过不同的设备端口,来访问页面,就属于不同的用户。即使现实中同一用户,使用了不同的设备,例如:我通过手机和电脑,各访问了一次,这也算不同的用户。

我没看过百度统计的原理,想到的唯一性,就是通过用户的 ip 和 user agent md下作为用户的唯一值(但这种应该相当的不准确,同一区域的ip可能都相同,加上访问的 user agent 重复性也太高,这种只适合粗略的统计下)。

同事可能了解过点,是给每个用户从后端设置上 cookie 来记录唯一用户。但是使用 cookie 的缺点是,当用户 "清除浏览器缓存",会将 cookie 清除掉。

开始百度,搜索到一篇问题:
	https://segmentfault.com/q/1010000000670397

里面提到了2个方案:
	evercookie:
		https://github.com/samyk/evercookie

	fingerprintjs:
		https://github.com/Valve/fingerprintjs

简单介绍下:
	evercookie:
		evercookie 是在浏览器中生成一个极其持久的 cookie。它的终极目标是,即使用户已经删除了标准的 cookie,Flash cookies,以及其他的一些相关数据,仍然能够识别出客户端的唯一性。

		evercookie 的实现原理是,将 cookies 数据存储到尽可能多的浏览器存储机制中。如果从任意的存储机制中,删除了 cookies 数据,只要有一个存储机制中的 cookies 数据是完好的,evercookie 都会在其他存储机制中,重新创建 cookies 数据。

		如果 Flash LSO、Silverlight 或 Java 机制可用,Evercookie 甚至可以在同一客户机上的不同浏览器之间传播 cookie!(这几个机制,支持 cookie 跨同一设备的不同浏览器)

		文章提到了,好多浏览器的 "存储机制",我们非常有必要了解下!!!
			HTTP Cookies
			Local Storage
			Session Storage
			Global Storage
			...

		还有未实现的技术:
			TLS Session Resumption
			HPKP
			...

		注意事项:
			Evercookie 可能会给我们和我们的用户带来潜在的问题:
				1>一些存储机制,会在客户端浏览器中,加载 Silverlight 或 Flash。在一些浏览器中,可能会加载的比较慢,并且伴随着大量的磁盘抖动。在更老的移动设备上,还可能会网站无法渲染。

				2>使用的 CSS History Knocking 技术,会在首次设置 cookie 时,产生大量的 HTTP 请求。

				3>在某些圈子里,认为使用 Evercookie 过于粗暴。所以,在生产环境中,使用 Evercookie,需要考虑我们的声誉和受众。

				4>浏览器供应商,正在尽最大努力,来填补 Evercookie 利用的许多漏洞技术。这对互联网发展来说是好事,但同时也意味着现在 evercookie 正常使用的技术,以后可能就失效了。(比较关键!)

		使用:
			<script type="text/javascript" src="evercookie.js"></script>
			<script>
				var ec = new evercookie();

				// 设置 cookie
				ec.set('id', '123456');

				// 获取 cookie,传递一个简单函数
				ec.get('id', function(value){
					console.log('cookie value is ' + value);
				});

				// 获取 cookie,传递一个高级函数(第二个参数,是 evercookie 所有的 "存储机制")
				ec.get('id', function(value, all_candidates){
					console.log('cookie value is ' + value);
					for(var i in all_candidates){
						document.write('storage mechanism ' + i + ' returned: ' + all_candidates[i] + '<br>');
					}	
				});
			</script>

		源码文件:
			git clone https://github.com/samyk/evercookie.git

		目录结构:
			assets/
			css/
			js/
			php/
			index.html

		简单解析:
			我们可以打开 index.html 查看,作者的使用方法:

			1>引入的 js 文件,包含的 java 相关的存储机制不了解:
				<script type="text/javascript" src="js/swfobject-2.2.min.js"></script>
				<script type="text/javascript" src="http://www.java.com/js/dtjava.js"></script>
				<script type="text/javascript" src="js/evercookie.js"></script>

			2>实例化时的配置:
				// 这里对应着我们下载的源码的访问目录(结合自己项目使用)
			    var ec = new evercookie({
			    	baseurl: '/evercookie', http://localhost/evercookie
			    	asseturi: '/evercookie/assets', http://localhost/evercookie/assets
			    	phpuri: '/evercookie/php' http://localhost/evercookie/php
			    });

		总结:
			evercookie 应该是个识别客户端唯一性的好方法,各种存储机制,最大程度上保证了可靠性。项目中应该可以采用。(不过目前我还没有在项目中使用,只是先记录个笔记,知道有这个方法!大家有兴趣可以自己尝试!)

	fingerprintjs:
		根据浏览器的 user agent、screen color depth、language、安装的支持 MIME 的插件、timezone offset,以及浏览器的一些其他能力,例如:local storage、session storage。然后使用了 'murmur' hash 函数,来生成唯一值。

		这个原理,其实和最初想的根据用户的 ip 和 user agent 来通过 md5 来生成唯一值,一个道理,不过作者加入了更多内容,来保证更精确,以及使用了 murmur 更快速!

		作者经过了4个月的生产测试,统计的结果是:
			1>89% 的准确率
			2>手机端的准确率好像很差
			3>如果你的应用是基于 PC,同时能忍受 10-12% 的误差,可以使用。(作者自己公司,最终移除了该方案!)

		fingerprintjs 作者写的关于 fingerprintjs 的博文,记录了自己的实现过程:
			http://valve.github.io/blog/2013/07/14/anonymous-browser-fingerprinting/

		hash 函数,为什么使用了 Murmur:
			https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed

		作者参考了 murmur 算法 javascript 的实现,将它添加到了 fingerprintjs 代码中
			https://github.com/garycourt/murmurhash-js

		为了抛弃对 jquery 的依赖,也在 fingerprintjs 实现了 each() 和 map() 函数,不依赖任何第三方类库

		使用方法,参考:
			http://valve.github.io/fingerprintjs/

		获取客户端唯一值:
			var fingerprint = new Fingerprint().get();

		自定义 hash 函数:
			var hasher = new function(value, seed){ return value.length % seed; }
			var fingerprint = new Fingerprint(hasher).get();

		查看了下源码,可自定义 options 有:

		/*
		    if (typeof options == 'object'){
		      	this.hasher = options.hasher;
		      	this.screen_resolution = options.screen_resolution;
		      	this.screen_orientation = options.screen_orientation;
		      	this.canvas = options.canvas;
		      	this.ie_activex = options.ie_activex;
		    } else if(typeof options == 'function'){
		      	this.hasher = options;
		    }
		*/

		1.options 可以只传递一个 function,即表示 hash 函数

		2.options 可以传递一个对象
			hasher - hash 函数(function)

			// 作者在文章中,还专门提到了 '屏幕分辨率' 的问题:
			// 最初也添加了屏幕分辨率,但一位同事建议可以在一台笔记本电脑上使用多台显示器,例如在办公室工作时连接外接显示器,所以将其删除。
			// 外接屏幕,其实还是同一个客户端,但是具有不同的分辨率,这里交给我们自己自定义了
			screen_resolution - 是否添加 '屏幕分辨率' 识别(boolean)
			screen_orientation - 是否添加 '屏幕方向' 识别(boolean)
			canvas - 是否添加 'canvas' 识别(boolean)
			ie_activex - 是否添加 'ActiveXObject' 识别(boolean)

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值