Ajax.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. 此函数为ajax区域 要求所有后台请求来自于这里
  3. 应该5秒内返回给用户一个提示信息。涉及到提示信息可以传递时间参数到此ajax,如果5秒未收到结果,则弹出重试的提示。
  4. ajax 跨域有问题 没有到回调里面去
  5. */
  6. /*
  7. 变量命名编写规范:
  8. 变量类型 变量名称
  9. string str
  10. object obj。
  11. Array arr
  12. Element el
  13. bool b
  14. 用户信息 userinfo
  15. 硬盘信息 diskinfo
  16. 好友信息 frindinfo
  17. 群信息 groupinfo
  18. 回调callback cb
  19. 函数 fun
  20. 错误 err
  21. 参数数组aruguments arg
  22. */
  23. //补充错误的定义。
  24. //错误状态写在r.request.status里面。如果r.request.status==200,则表示成功。其余状态码表示有错误,如果是我们系统发生错误,统一状态码为500,即r.request.status==500,其他由web服务器自己决定。
  25. //详细错误信息在r.value里面.
  26. Namespace.register("U.A"); //A为Ajax简写
  27. //所有请求的ajax对象.
  28. U.A.allAjaxRequest =
  29. {
  30. requestNumber: 0, //总共请求次数
  31. requestObject: [], //请求的所有ajax对象
  32. forrequest: 0 //可能存在的循环请求的次数
  33. };
  34. //服务器返回值结构图
  35. /*_returnobj = { //返回的ajax对象
  36. httpRequest: ajaxobject, //xmlrequest对象
  37. status: 200, //服务器响应的状态 200成功,其他的都是失败
  38. value: null, //服务器返回的值
  39. context: cbparams //回调函数的参数
  40. };*/
  41. //开发后端程序时需要返回的结构体
  42. var serverInfo = {
  43. affectRows: null, //数据库影响行数,插入,修改,删除时,如果大于0,表示成功,否则,表示失败
  44. value: null, //数据库查询时的取值。如果错误,请查看其他变量的值
  45. error: null, //数据库及服务器错误信息
  46. statusCode: null //服务器状态码,服务器响应的状态 200成功,其他的都是失败
  47. }
  48. //uform前端ajax返回值结构体
  49. var serverReturnObj = { //返回的ajax对象
  50. httpRequest: null, //xmlrequest对象,前台标准
  51. status: 200, //服务器响应的状态 200成功,其他的都是失败,,这是历史遗留,以后要删除
  52. serverInfo: serverInfo, //等于后端结构体
  53. value: null, //服务器返回的值,历史遗留,以后删除
  54. context: null //回调函数的参数,前台标准
  55. };
  56. //#region ajax
  57. /**
  58. * ajax初始化区域
  59. *
  60. * @param {string} 访问的地址
  61. * @param {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
  62. * @param {function} 回调函数
  63. * @param {array} 函数传参
  64. * @param {object} 需要写入的header对象
  65. * @returns {object} ajax对象
  66. */
  67. U.A.Request = function (url, params, cb, cbparams, header) {
  68. //判断是否为攻击
  69. if (U.A.Request.ifAttack()) {
  70. var _isdomain = U.A.Request.isDomain(url); //判断请求的ajax是否是跨域请求,这里是做跨域请求的方案
  71. //如果是在本域名下请求的处理,或者是跨域请求,没有做其他跨域方案。
  72. if (_isdomain == 1) {
  73. var _header = header || {}, //ajax对象header的设置处理
  74. _ajaxtype = _header.type || "POST", //设置ajax请求的类型 Get 或者是post
  75. _isasync = U.UF.C.isFunction(cb), //判断请求为异步函数同步
  76. _params = U.A.Request.toAjaxFormat(params); //把数组传参转化成ajax传参
  77. //创建一个全兼容的ajax对象
  78. var _ajaxobject = U.A.Request.createAjaxObject(url);
  79. //记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
  80. U.A.Request.attack(url, params, cb, cbparams, header, _ajaxobject);
  81. //如果请求的类型是get,那么请求拼接链接
  82. if (_ajaxtype.toUpperCase() == "GET") {
  83. url += "?" + _params;
  84. }
  85. //打开请求,设置ajax请求方法 url 是否异步
  86. _ajaxobject.open(_ajaxtype, url, _isasync);
  87. //给ajax对象的header设置值
  88. U.A.Request.writeHeader(_ajaxobject, _header);
  89. //发送请求
  90. _ajaxobject.send(_params);
  91. //等待服务器返回的数据库的结果。
  92. //如果是异步,那么用异步的处理
  93. if (_isasync) {
  94. U.A.Request.asyn(_ajaxobject, cb, cbparams);
  95. }
  96. //如果是同步的处理
  97. else {
  98. return U.A.Request.getData(_ajaxobject, null);
  99. }
  100. }
  101. else {
  102. return U.A.Request.handleDomain(url, params, cb, cbparams, header, _isdomain);
  103. }
  104. }
  105. }
  106. /**
  107. * 自定义传参ajax初始化区域
  108. * 由于U.A.Request发送的请求默认传递为mode传参后的拼接参数,但有部分接口的参数名并不为mode,
  109. * 因此定义此接口为自定义请求所服务。
  110. * @param {string} 访问的地址
  111. * @param {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
  112. * @param {function} 回调函数
  113. * @param {array} 函数传参
  114. * @param {object} 需要写入的header对象
  115. * @returns {object} ajax对象
  116. */
  117. U.A.Request.Post = function (url, params, cb, cbparams, header) {
  118. //判断是否为攻击
  119. if (U.A.Request.ifAttack()) {
  120. var _isdomain = U.A.Request.isDomain(url); //判断请求的ajax是否是跨域请求,这里是做跨域请求的方案
  121. //如果是在本域名下请求的处理,或者是跨域请求,没有做其他跨域方案。
  122. if (_isdomain == 1) {
  123. var _header = header || {}, //ajax对象header的设置处理
  124. _ajaxtype = _header.type || "POST", //设置ajax请求的类型 Get 或者是post
  125. _isasync = U.UF.C.isFunction(cb), //判断请求为异步函数同步
  126. _params = U.A.Request.Post.toAjaxFormat(params); //把数组传参转化成ajax传参
  127. //创建一个全兼容的ajax对象
  128. var _ajaxobject = U.A.Request.createAjaxObject(url);
  129. //记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
  130. U.A.Request.attack(url, params, cb, cbparams, header, _ajaxobject);
  131. //打开请求,设置ajax请求方法 url 是否异步
  132. _ajaxobject.open(_ajaxtype, url, _isasync);
  133. //给ajax对象的header设置值
  134. U.A.Request.writeHeader(_ajaxobject, _header);
  135. //发送请求
  136. _ajaxobject.send(_params);
  137. //等待服务器返回的数据库的结果。
  138. //如果是异步,那么用异步的处理
  139. if (_isasync) {
  140. U.A.Request.asyn(_ajaxobject, cb, cbparams);
  141. }
  142. //如果是同步的处理
  143. else {
  144. return U.A.Request.getData(_ajaxobject, null);
  145. }
  146. }
  147. else {
  148. return U.A.Request.handleDomain(url, params, cb, cbparams, header, _isdomain);
  149. }
  150. }
  151. }
  152. /**
  153. * Post请求数据拼接
  154. *
  155. * @param {array} 数组的传参
  156. */
  157. U.A.Request.Post.toAjaxFormat = function (params) {
  158. var _key;
  159. var _params = '';
  160. for (_key in params) {
  161. _params += _key + '=' + encodeURIComponent(encodeURIComponent(params[_key])) + '&';
  162. }
  163. return _params.substr(0, _params.length - 1);
  164. }
  165. /**
  166. * 记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
  167. *
  168. * @param {string} 访问的地址
  169. * @param {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
  170. * @param {function} 回调函数
  171. * @param {array} 函数传参
  172. * @param {object} 需要写入的header对象
  173. * @returns {object} ajax对象
  174. */
  175. U.A.Request.attack = function (url, params, cb, cbparams, header, ajaxobject) {
  176. var _preajax = U.A.allAjaxRequest.requestObject[U.A.allAjaxRequest.requestObject.length - 1], //上一个请求
  177. _ajaxarray = {
  178. "win": window, //执行的域
  179. "ajax": ajaxobject, //ajax对象
  180. "url": url, //后台的地址
  181. "params": params, //后台的传参
  182. "cb": cb, //执行后的回调
  183. "cbparams": cbparams, //回调函数的传参
  184. "header": header, //ajax的header的处理
  185. "time": new Date().getTime() //ajax创建的时间
  186. };
  187. U.A.allAjaxRequest.requestNumber += 1; //这个是总的请求数
  188. U.A.allAjaxRequest.requestObject.push(_ajaxarray); //把ajax对象添加到全局
  189. //如果有上一个ajax请求的处理
  190. if (_preajax) {
  191. //如果第一次请求和第二次请求时间差为50毫秒的话,这里就默认是循环请求
  192. if (_ajaxarray.time - _preajax.time < 50) {
  193. U.A.allAjaxRequest.forrequest += 1;
  194. }
  195. else {
  196. U.A.allAjaxRequest.forrequest = 0;
  197. }
  198. }
  199. return _ajaxarray;
  200. }
  201. /**
  202. * ajax把参数转成ajax的传参
  203. * @param {array} 数组的传参
  204. *
  205. */
  206. U.A.Request.toAjaxFormat = function (params) {
  207. params = params || [];
  208. var _userinfo,
  209. _params = "mode=" + U.UF.C.urlEncode(params.concat()); //参数加密处理拼接处理
  210. try {
  211. //由于1473后台对loginid 、 userid 、pageid 、systemid是直接通过url获取的,没有进行传参,那么下面就是进行1473 url的拼接
  212. if (parent && parent.US) { //如果有parent.US那么就是1473的项目
  213. _userinfo = parent.US.userInfo; //获取用户的信息
  214. //如果用户的信息存在那么拼接用户的信息
  215. if (_userinfo && _userinfo.UserId) {
  216. _params += "&UserId=" + _userinfo.UserId + "&LoginId=" + _userinfo.LoginId;
  217. }
  218. //设置1473项目传参的id
  219. _params += "&PageId=" + US.pageId + "&SystemId=" + US.systemId;
  220. }
  221. } catch (e) { }
  222. return _params;
  223. }
  224. /**
  225. * 创建ajax请求对象 XMLHttpRequest或者 ActiveXObject对象
  226. * @param {string} ajaxurl的地址
  227. *
  228. */
  229. U.A.Request.createAjaxObject = function (url) {
  230. //ie8,ie9跨域兼容
  231. var _locationurl = window.location ? (window.location.protocol + "//" + window.location.host) : ""; //url的链接
  232. if (url.indexOf(_locationurl) == -1 && window.XDomainRequest) {//在ie8、9中允许用ajax跨域访问 但是不支持XMLHttpRequest跨域而是一个新的函数XDomainRequest,后面废除了。
  233. return new window.XDomainRequest();
  234. }
  235. //这里创建Ajax对象
  236. try { return new XMLHttpRequest(); } catch (e) { }
  237. //ie6以下的浏览器处理,包含一些可解析脚本插件处理,//ie6系列等直接脚本的浏览器支持的插件
  238. //Internet Explorer
  239. try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) { }
  240. try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { }
  241. try { return new ActiveXObject('MSXML3.XMLHTTP'); } catch (e) { }
  242. try { return new ActiveXObject('MSXML.XMLHTTP'); } catch (e) { }
  243. try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
  244. try { return new ActiveXObject('MSXML2.ServerXMLHTTP'); } catch (e) { }
  245. //alert("你的浏览器不支持xmlhttp对象,所以一些功能无法使用,建议使用高版本的浏览器!!");
  246. }
  247. /**
  248. * 给ajax对象写入head
  249. * @param {object} ajax对象
  250. * @param {object} 需要写入的header
  251. */
  252. U.A.Request.writeHeader = function (ajax, header) {
  253. header["CONTENT-TYPE"] = header["CONTENT-TYPE"] || "application/x-www-form-urlencoded;charset=UTF-8"; //请求写入数据的格式,必须传值,否则后台获取值会报错
  254. //header["Connection"] = "keep-alive";
  255. header["timeout"] = 10000;
  256. try {
  257. header["type"] = null;
  258. delete header["type"];
  259. }
  260. catch (e) { }
  261. //循环给ajax对象设置header
  262. for (var i in header) {
  263. try {
  264. //ajax属性里面有方法的设置
  265. if (i in ajax) {
  266. ajax[i] = header[i];
  267. }
  268. //不是ajax属性的设置header
  269. else {
  270. ajax.setRequestHeader(i, header[i]);
  271. }
  272. }
  273. catch (e) { }
  274. }
  275. // 指定服务器返回数据的MIME类型 firfox设置兼容,不设置frifox浏览器后台无法获取值
  276. if (ajax.overrideMimeType) {
  277. if (header["responseType"] == "blob") {
  278. ajax.overrideMimeType("text/plain; charset=x-user-defined");
  279. } else {
  280. ajax.overrideMimeType("text/html");
  281. }
  282. }
  283. }
  284. /**
  285. * ajax异步处理函数
  286. * @param {object} ajax对象
  287. * @param {function} 回调函数
  288. * @param {array} 回调参数
  289. */
  290. U.A.Request.asyn = function (ajaxobject, cb, params) {
  291. //判断是否需要loading处理,如果需要loading处理,那么在第一个元素中添加loading
  292. if (params && params[0] && U.UF.C.isElement(params[0])) {
  293. U.UF.DL.loading(params[0]);
  294. }
  295. //正常的ajax的回调处理
  296. if (ajaxobject.onreadystatechange !== undefined) {
  297. //设置ajax回调处理
  298. ajaxobject.onreadystatechange = function () {
  299. if (ajaxobject.readyState == 4) { //已经加载成功
  300. //判断是否有loading处理,如果有则移除
  301. if (params && params[0] && U.UF.C.isElement(params[0])) {
  302. U.UF.DL.uploading(params[0]);
  303. }
  304. var _data = U.A.Request.getData(ajaxobject, params); //获取ajax的返回值
  305. cb.call(cb, _data); //回调处理
  306. }
  307. }
  308. //ajax超时处理
  309. ajaxobject.ontimeout = function () {
  310. return false;
  311. }
  312. }
  313. //ajax支持onload事件的处理,由于ie8、ie9跨域的XDomainRequest对象只支持onload
  314. else {
  315. ajaxobject.ontimeout = function () { }
  316. //错误处理,下面用onreadystatechange已经把这个功能包含进去
  317. ajaxobject.onerror = function () {
  318. ajaxobject.status = 500; //由于这个请求对象不会自动设置500错误,但是为了统一判断,这里设置默认的错误500
  319. cb.call(cb, { //返回的ajax对象
  320. httpRequest: ajaxobject, //xmlrequest对象
  321. status: { //服务器响应的状态 200成功,其他的都是失败
  322. "status": ajaxobject.status,
  323. "statusText": ajaxobject.statusText
  324. },
  325. value: null, //服务器返回的值
  326. context: params //回调函数的参数
  327. }); //回调处理
  328. };
  329. //设置ajax回调处理
  330. ajaxobject.onload = function () {
  331. //判断是否有loading处理,如果有则移除
  332. if (params && params[0] && U.UF.C.isElement(params[0])) {
  333. U.UF.DL.uploading(params[0]);
  334. }
  335. var _data = U.A.Request.getData(ajaxobject, params); //获取ajax的返回值
  336. cb.call(cb, _data); //回调处理
  337. }
  338. }
  339. }
  340. /**
  341. * 获取ajax的值
  342. * @param {object} ajax对象
  343. * @param {function} 回调函数
  344. */
  345. U.A.Request.getData = function (ajaxobject, cbparams) {
  346. var _data, //服务器返回的值
  347. _returnobj = { //返回的ajax对象
  348. httpRequest: ajaxobject, //xmlrequest对象
  349. status: 200, //服务器响应的状态 200成功,其他的都是失败
  350. value: null, //服务器返回的值
  351. context: cbparams //回调函数的参数
  352. };
  353. //返回值的正确处理
  354. if (ajaxobject.status == 200 || ajaxobject.status == null) {
  355. //服务器返回的是xml对象的处理
  356. if (ajaxobject.responseXML && ajaxobject.responseXML.xml) {
  357. _data = ajaxobject.responseXML.xml; //xml的值
  358. }
  359. //服务器返回的是string的处理
  360. else {
  361. _data = U.UF.C.toJson(ajaxobject.responseText); //获取转化成ajax的对象
  362. }
  363. _returnobj.value = _data; //设置服务器返回的值
  364. }
  365. //错误处理
  366. else {
  367. //ajax错误处理
  368. _returnobj.status = {
  369. "status": ajaxobject.status,
  370. "statusText": ajaxobject.statusText
  371. };
  372. }
  373. //关闭连接,释放资源
  374. if (ajaxobject.abort) {
  375. ajaxobject.abort();
  376. }
  377. //请求得到值的整个过程的时间差处理
  378. U.A.Request.timeSpan(ajaxobject, _returnobj);
  379. //返回得到的值
  380. return _returnobj;
  381. }
  382. /**
  383. * 判断ajax是否跨域处理
  384. * @param {string} 请求的地址
  385. *返回值:1相同域名不跨域*2为跨子域,3为完全跨域
  386. */
  387. U.A.Request.isDomain = function (url) {
  388. var _frame,
  389. _a = $$("a", { "href": url }) //创建一个a标签能得到 url请求的地址的域
  390. ;
  391. //如果是直接浏览器打开文件的方式 如e:/a.html这样打开的则没有window.location
  392. if (window.location) {
  393. //相同域名也不跨子域的情况
  394. if (_a.host.indexOf(document.domain) >= -1) {
  395. return 1;
  396. }
  397. //相同域名也跨子域的情况
  398. else if (window.location.host.split(".").slice(-2).join(".") == _a.hostname.split(".").slice(-2).join(".")) {
  399. _frame = window.frames; //所有加载的域,对1473域下所有iframe进行循环,目的是找到可跨域的iframe。
  400. //循环所有可跨域的iframe进行处理
  401. for (i = 0; i < _frame.length; i++) {
  402. try {
  403. if (_frame[i].location.host && _a.host.indexOf(_frame[i].location.host) == 0) { //找到指定的跨域
  404. return 2; //跨域获取
  405. }
  406. }
  407. catch (e) {
  408. }
  409. }
  410. }
  411. }
  412. //完全跨域的情况,这里的要求是必须创建iframe id和name为U_Domain的
  413. // if ($("#U_Domain")[0]) {
  414. // return 3;
  415. //}
  416. return 1; //如果开发者跨域了,也没有用跨域解决方案,也默认给他调用ajax的方法,因为在高版本的浏览器中已经支持xmlrequest跨域了
  417. }
  418. /**
  419. * ajax异步处理的方式
  420. *
  421. * @param {string} 访问的地址
  422. * @param {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
  423. * @param {function} 回调函数
  424. * @param {array} 函数传参
  425. * @param {object} 需要写入的header对象
  426. * @param {object} 跨域的方式 2 相同域名也跨子域的情况 3 完全跨域的情况
  427. */
  428. U.A.Request.handleDomain = function (url, params, cb, arg, header, isdomain) {
  429. var _newsinfo,
  430. _a = $$("a", { "href": url }), //创建一个a标签能得到 url请求的地址的域
  431. _frame;
  432. //相同域名也跨子域的情况
  433. if (isdomain == 2) {
  434. _frame = window.frames; //所有加载的域,对1473域下所有iframe进行循环,目的是找到可跨域的iframe。
  435. //循环所有可跨域的iframe进行处理
  436. for (i = 0; i < _frame.length; i++) {
  437. try {
  438. if (_a.hostname.indexOf(_frame[i].location.hostname) == 0) { //找到指定的跨域
  439. return _frame[i].U.A.Request(url, params, cb ? function (data) { setTimeout(function () { cb.call(window, data) }); } : null, arg, header); //跨域获取
  440. }
  441. }
  442. catch (e) {
  443. }
  444. }
  445. }
  446. //完全跨域的情况,这里的要求是必须创建iframe id和name为U_Domain的
  447. else if (isdomain == 3) {
  448. //判断是否需要loading处理,如果需要loading处理,那么在第一个元素中添加loading
  449. if (params && U.UF.C.isElement(params[0])) {
  450. U.UF.DL.uploading(params[0]);
  451. }
  452. //跨域执行ajax处理 fun, issender, iframeid, url, id
  453. _newsinfo = new U.UF.EV.message(
  454. function (data, id, cookie) { //接受到跨域的ajax的回调处理 data[0]是执行ajax后台返回的值 data[1]是执行的cookie处理
  455. //后台设置了cookie 前台同时响应
  456. if (cookie == "") { //删除cookie的值
  457. U.UF.Cookie.del(cookie);
  458. }
  459. //如果在和后台交互的过程设置了cookie,那么这里需要设置
  460. else {
  461. U.UF.Cookie.set(cookie);
  462. }
  463. var _data = { //返回的ajax对象
  464. httpRequest: null, //xmlrequest对象
  465. status: 200, //服务器响应的状态 200成功,其他的都是失败
  466. value: data, //服务器返回的值
  467. context: arg //回调函数的参数
  468. };
  469. cb.call(cb, _data); //回调处理
  470. }, true, "domain", "U_Domain");
  471. //跨域传参
  472. _newsinfo.post([url, params], "domain");
  473. }
  474. return false; //如果开发者跨域了,也没有用跨域解决方案,也默认给他调用ajax的方法,因为在高版本的浏览器中已经支持xmlrequest跨域了
  475. }
  476. /**
  477. * 判断用户是否连续发送ajax请求到后台,如果是我们视为攻击,返回false,否则是true
  478. */
  479. U.A.Request.ifAttack = function () {
  480. var _isfor = U.A.allAjaxRequest.forrequest < 50; //获取是否循环进行ajax处理,如果超过50次我们认为是攻击ajax
  481. //如果为攻击ajax,那么就等待清楚攻击
  482. if (!_isfor) {
  483. setTimeout(function () { U.A.allAjaxRequest.forrequest = 0; })
  484. }
  485. return _isfor;
  486. }
  487. /**
  488. * 请求时间差处理
  489. * @param {object} ajax对象
  490. * @param {object} 服务器返回值
  491. */
  492. U.A.Request.timeSpan = function (ajaxobject, request) {
  493. var i,
  494. _timespan,
  495. _arr = U.A.allAjaxRequest.requestObject; //所有请求的ajax对象
  496. //循环数组的对象
  497. for (i = 0; i < _arr.length; i++) {
  498. try {
  499. //整个ajax的对象
  500. if (_arr[i].ajax == ajaxobject) {
  501. _timespan = new Date().getTime() - _arr[i].time; //请求时间差
  502. U.UF.C.console({ "timespan": _timespan, "request": request }); //控制台输出请求的时间差和值
  503. }
  504. } catch (e) { }
  505. }
  506. }
  507. //#endregion