AJax技术

我在同步 ajax 的 cookie 上栽了个无语的跟头

字号+ 作者:H5之家 来源:H5之家 2017-10-25 17:00 我要评论( )

前言遇到这种问题纯属无奈,前端的浏览器兼容性一直是一个让人头痛的问题仅以此文记录如此尴尬无奈的一天。哪里替大伙儿解闷T_T场景再现同事:快来!快来!线上

前言

遇到这种问题纯属无奈,前端的浏览器兼容性一直是一个让人头痛的问题

仅以此文记录如此尴尬无奈的一天。哪里替大伙儿解闷T_T

场景再现

同事:快来!快来!线上出问题了!!
我:神马?! 咩?! WHAT?! なに?!
同事:是这次发布造成的?
我:回滚!回滚!(为什么要在快吃饭的时候掉链子!顾不上肚子了!快查吧)
......

一通混乱的对话后只能静下心来“扫雷”了。

回滚、代理、抓包、对比、单因子排查。。。

一套组合拳打完,大概一炷香的时间,终于找到了破绽,竟然是 ajax 的同步回调的问题!不合理啊!不应该啊!还有这种操作!

问题复现一句话概括问题

使用 ajax 做“同步”请求,此请求会返回一个 cookie,在success回调中读取 此目标cookie 失败!success回调执行结束后 document.cookie 才会被更新

影响范围

所有在本同步请求回调内预读取本请求返回的 cookie 都会产生问题。

PC 端和 Android 端影响范围小,属于偶现。

IOS 端是重灾区,出来 Chrome 和 Safari 浏览器外的绝大多说浏览器都会出现此问题,并且 App 内置的 Webview 环境同样不能幸免。

但是

半壁江山都沦陷了,所以,此操作能不做就不做。

追因溯果

小范围的兼容问题我姑且可以饶你,奈何你如此猖狂,怎能任你瞒天过海!

纵向对比

排除一些干扰项,还原其本质,我们分别用框架nej,jQuery和js写几个相同功能的“同步” demo,走着瞧着。。

【nej.html】使用 NEJ 库

<!DOCTYPE html> <html> <head> <title>nej</title> <meta charset="utf-8" /> </head> <body> test <script src="http://nej.netease.com/nej/src/define.js?pro=./"></script> <script> define([ '{lib}util/ajax/xdr.js' ], function () { var _j = NEJ.P('nej.j'); _j._$request('/api', { sync: true, method: 'POST', onload: function (_data) { alert("cookie: " + document.cookie) } }); }); </script> </body> </html>

【jquery.html】使用 jQuery 库

<!DOCTYPE html> <html> <head> <title>jquery</title> <meta charset="utf-8" /> </head> <body> jquery <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> $.ajax({ url: '/api', async: false, method: 'POST', success: function (result) { alert("cookie: " + document.cookie) } }); </script> </body> </html>

【js.html】自己实现的 ajax 请求函数

<!DOCTYPE html> <html> <head> <title>JS</title> <meta charset="utf-8" /> </head> <body> js <script> var _$ajax = (function () { /** * 生产XHR兼容IE6 */ var createXHR = function () { if (typeof XMLHttpRequest != "undefined") { // 非IE6浏览器 return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined") { // IE6浏览器 var version = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", ]; for (var i = 0; i < version.length; i++) { try { return new ActiveXObject(version[i]); } catch (e) { return null } } } else { throw new Error("您的系统或浏览器不支持XHR对象!"); } }; /** * 将JSON格式转化为字符串 */ var formatParams = function (data) { var arr = []; for (var name in data) { arr.push(name + "=" + data[name]); } arr.push("nocache=" + new Date().getTime()); return arr.join("&"); }; /** * 字符串转换为JSON对象,兼容IE6 */ var _getJson = (function () { var e = function (e) { try { return new Function("return " + e)() } catch (n) { return null } }; return function (n) { if ("string" != typeof n) return n; try { if (window.JSON && JSON.parse) return JSON.parse(n) } catch (t) { } return e(n) }; })(); /** * 回调函数 */ var callBack = function (xhr, options) { if (xhr.readyState == 4 && !options.requestDone) { var status = xhr.status; if (status >= 200 && status < 300) { options.success && options.success(_getJson(xhr.responseText)); } else { options.error && options.error(); } //清空状态 this.xhr = null; clearTimeout(options.reqTimeout); } else if (!options.requestDone) { //设置超时 if (!options.reqTimeout) { options.reqTimeout = setTimeout(function () { options.requestDone = true; !!this.xhr && this.xhr.abort(); clearTimeout(options.reqTimeout); }, !options.timeout ? 5000 : options.timeout); } } }; return function (options) { options = options || {}; options.requestDone = false; options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; options.contentType = options.contentType || "application/x-www-form-urlencoded"; options.async = options.async; var params = options.data; //创建 - 第一步 var xhr = createXHR(); //接收 - 第三步 xhr.onreadystatechange = function () { callBack(xhr, options); }; //连接 和 发送 - 第二步 if (options.type == "GET") { params = formatParams(params); xhr.open("GET", options.url + "?" + params, options.async); xhr.send(null); } else if (options.type == "POST") { xhr.open("POST", options.url, options.async); //设置表单提交时的内容类型 xhr.setRequestHeader("Content-Type", options.contentType); xhr.send(params); } } })(); _$ajax({ url: '/api', async: false, type: 'POST', success: function (result) { alert("cookie: " + document.cookie) } }); </script> </body> </html>

三个文件都是一样的,在html 加载完之后发起一个同步请求,该请求会返回一个 cookie,在回调中将document.cookie打印出来,检测是否已经在回调时写入的了 cookie。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML / CSS技巧 – 可滚动的 tbody(漂亮表格)

    HTML / CSS技巧 – 可滚动的 tbody(漂亮表格)

    2017-10-13 12:05

  • 【htmlunit开发技巧】

    【htmlunit开发技巧】

    2017-10-06 11:01

  • CDN后用Ajax动态提交、显示文章阅读量,cookies避免重复刷新

    CDN后用Ajax动态提交、显示文章阅读量,cookies避免重复刷新

    2017-09-04 17:04

  • jquery ajax 返回执行js 脚本

    jquery ajax 返回执行js 脚本

    2017-08-27 14:04

网友点评