JS跨域写cookie
背景与需求场景
用户每次访问iqiyi的页面,js都会发送一条记录本次pv的pingback请求到日志服务器。pv日志中除了记录当前访问页面的url、前一个页面的url即document.referrer,还记录了登陆页的来源,即session来源:如果用户最初是从百度搜索iqiyi,点击百度搜索结果页面中的链接,然后打开了iqiyi的页面(为登陆页),session来源即为百度搜索结果页。用户在iqiyi登陆页及后续iqiyi网站上的访问pv日志中都要把session来源给发送到日志服务器,供统计网站用户来源。
上述是背景。技术实现时,是把session来源记录在本地cookie中:用户每次访问iqiyi的页面时,JS都会检查当前页面的document.referrer,如果为空串,就记为DIRECT,表示直达用户,并写入cookie。如果当前页面的document.referrer不为空,就检查cookie中的值和document.referrer,如果两个值是同属于一个根域名iqiyi.com,说明是站内跳转,就使用cookie中的值发送pv日志;如果不属于同一个根域名,说明是站外导流过来的,就用document.referrer发送pv日志并更新cookie。
上面的逻辑就是线上运行的session来源判定逻辑。
直到这次统计的产品人员提出新需求:把pps.tv当做站内来进行处理,从pps.tv跳到iqiyi.com时,把iqiyi.com的session来源取值为pps.tv的session来源。即:当用户从百度搜索pps,点击百度搜索结果页中的链接,打开了pps.tv的网页,然后用户点击pps.tv网页中的链接来到iqiyi.com,在发送iqiyi.com的pv日志时要发送百度搜索结果页的url,而不是pps.tv页面的url。从iqiyi.com跳到pps.tv时也如是处理。
解决方案
尽管pps.tv和iqiyi.com运行的是同一套JS代码,但是cookie是种在不同的根域名下的。需要在写本域的cookie时同步写另外一个域的cookie,这涉及到跨域操作cookie了。
解决方案是:在服务端上存放一个代理页面proxy.html,专门用来从url中接收欲写入的cookie的key和value信息,并写入到自身根域名下。
举例子来说就是:从百度搜索结果页打开链接到pps.tv的网页时,pps.tv中的js代码新建一个iframe,src为http://www.iqiyi.com/common/proxy.html#QC007=http://www.baidu.com/s?wd=pps.tv,这个proxy.html里面的js代码从location.hash中解析出QC007和http://www.baidu.com/s?wd=pps.tv,把二者作为cookie的key和value写入到iqiyi.com域名下,实现同步cookie到iqiyi.com。
同样从百度搜索结果页面打开链接到iqiyi.com的网页时,iqiy.com中的js用iframe请求http://www.pps.tv/common/proxy.html#QC007=http://www.baidu.com/s?wd=iqiyi并同步cookie到pps.tv域名下。
问题与修复方案
用iframe同步跨域cookie看上去很理想,用chrome/Firefox/IE8测了一下是符合预期的。
直到用IE6试了一把,发现对http://www.iqiyi.com/common/proxy.html和http://www.pps.tv/common/proxy.html的iframe请求都发送了,但是cookie没同步到对方域名下,发送的pv日志中的session来源字段都是"DIRECT"。
到网上搜索了一下,发现是IE6默认阻止了第三方cookie了,需要服务端给响应的设置P3P header。

我试着把IE6的隐私选项设置为最低,cookie就能同步了,pv日志中session来源字段能发送正确值了。但用户不可能都会主动修改浏览器选项,所以还是要服务端配合改动,给这两个iframe的响应加P3P header。如下所示:


这样,在IE67上也能达到同步cookie的效果了。
blog comments powered by Disqus