错误描述
极个别用户用IE浏览器访问页面,在加载页面的过程中,会出现如下错误提示:
错误分析
1、在页面使用jquery.cookie.js读cookie,加载页面时会查找cookie进行判断。
if(\$.cookie("resultDescription")!=null) { _tips.html(\$.cookie("resultDescription")).show(); \$("#txtName").val(\$.cookie("userName")); \$.cookie("resultDescription", null); \$.cookie("userName", null); \$(".tips-username").show();//显示忘记用户名 \$(".tips-ask").show(); }
2、jquery.cookie.js内部实现方式是根据key遍历查找header中所有的cookie,并对取到的值进行decodeURIComponent解码。
// key and possibly options given, get cookie... options = value || {}; var decode = options.raw ? function(s) { return s; } : decodeURIComponent; var pairs = document.cookie.split('; '); for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined }
3、用户用ie浏览器访问该页面满足以下条件就会出现以上错误提示。
1)用户浏览器中存在未知来源的cookie A(key=resultDescription,而value=被gb2312等编码过后的值)。
2)A的domain属性(domain=”.123.com“)与我们站点相同(domain=”.123.com“),即我们是可以读到这个A的。
在重现过程中发现好玩点:用户从FF浏览器访问页面,对于浏览器中存在其他域名所设定domain=”.123.com“的cookie是不会读取的,故没有任何错误,不过是xxx.123.com创建就可以访问了,故会出现错误了;
用户用IE浏览器中只要浏览器存在domain=”.123.com“,无论是谁存入的都是直接访问的,不过体现就不一样的了。
重现问题如下(以下每步操作过后都是会清理cookie的):
protected void AddCookie_Click(object sender, EventArgs e) { HttpContext.Current.Response.Cookies.Add(new HttpCookie("resultDescription", HttpUtility.UrlEncode("中国", Encoding.GetEncoding("GB2312"))) { Expires = DateTime.Now.AddDays(2),Domain = ".123.com"}); Response.Redirect("https://xxx.123.com/"); }
解决方案
jquery.cookie.js本身是通过遍历header中的cookie来查找解码后的key对应的值,再对值解码,如果是读到的cookie本身是由该插件插入到浏览器的就没有问题,而我们并不排除有由后台插入的cookie被读到,故需要修改jquery.cookie.js文件的逻辑,在编码处增加try{}catch(e){}操作。
/*! * jQuery Cookie Plugin * https://github.com/carhartl/jquery-cookie * * Copyright 2011, Klaus Hartl * Dual licensed under the MIT or GPL Version 2 licenses. * http://www.opensource.org/licenses/mit-license.php * http://www.opensource.org/licenses/GPL-2.0 */ (function ($) { $.cookie = function (key, value, options) { // key and at least value given, set cookie... if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { options = $.extend({}, options); if (value === null || value === undefined) { options.expires = -1; } if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } value = String(value); return (document.cookie = [ encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), options.expires ? '; expires='+options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // key and possibly options given, get cookie... options = value || {}; var decode = options.raw ? function (s) { return s; } : decodeURIComponent; var pairs = document.cookie.split('; '); for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { try { if (decode(pair[0]) === key) { var val = decode(pair[1] || ''); return val; } // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined } catch (e) { } } return null; }; })(jQuery);