Bootstrap

Ajax通讯异常12002,前端MVC框架[02] 发送AJAX请求及建立连接池

前端MVC框架[02] 发送AJAX请求及建立连接池

默认分类 2012-10-11 07:51:28

<

ol start='100' class='dp-xml'>

/

异步请求管理器

/

var Requester = {

/

全局事件处理接口 注:不支持onsuccess

@Map{'ontimeout':function(){},'onfailure':function(){}}

/

handler:{},

/

获取XMLHttpRequest对象

@return{XMLHttpRequest} XMLHttpRequest对象

@description使用缓存模式避免每次都检测浏览器类型

*/

createXHRObject: function () {

var me = this,

i,

list,

len,

xhr = null,

methods = [

function () {returnnewXMLHttpRequest();},

function () {returnnewActiveXObject('Msxml2.XMLHTTP');},

function () {returnnewActiveXObject('Microsoft.XMLHTTP');}

];

for(i = 0, len = methods.length; i 

try {

xhr = methodsi;

this.createXHRObject = methods[i];

break;

} catch (e) {

continue;

}

}

if(!xhr) {

thrownewError(100000,'Requester.createXHRObject() fail. Your browser not support XHR.');

}

xhr.eventHandlers = {};

xhr.fire = me.creatFireHandler();

returnxhr;

},

/

* 生成新的触发事件方法

*

* @param{String} type 事件类型

*/

creatFireHandler: function(){

returnfunction (type) {

type = 'on'+ type;

var xhr = this,

handler = xhr.eventHandlers[type],

globelHandler = window.Requester.handler[type];

// 不对事件类型进行验证

if(handler) {

if(xhr.tick) {

clearTimeout(tick);

}

if(type !='onsuccess') {

handler(xhr);

} else{

//处理获取xhr.responseText导致出错的情况,比如请求图片地址.

try {

xhr.responseText;

} catch(error) {

returnhandler(xhr);

}

var text = xhr.responseText.replace(/^\s+/ig, "");

if(text.indexOf('{') === 0){

//{success:true,message:

//插入表单验证错误提示

var JSONParser;

try {

JSONParser = newFunction("return "+ text +";");

data = JSONParser();

}

//如果json解析出错则尝试移除多于逗号再试

catch (e){

JSONParser = newFunction("return "+ window.Requester.removeJSONExtComma(text) +";");

data = JSONParser();

}

if(String(data.success).replace(/\s/ig,'').toLowerCase() !=='true') {

// 当后端验证失败时

if(Requester.backendError) {

Requester.backendError(data);

}

}

handler(data);

}else{

handler(text);

}

}

}

// 检查是否配置了全局事件

elseif(globelHandler) {

//onsuccess不支持全局事件

if(type =='onsuccess') {

return;

}

globelHandler(xhr);

}

};

},

/

检测是否有空闲的XHR或创建新对象

@afterRequester

@comment使用Facade外观模式修改Requester.request方法

以增加路径权限判断

/

getValidXHR: function () {

var me = this;

returnme.createXHRObject();

},

/

* request发送请求

*

* @url{String} 请求的URL

* @options{Map} POST的参数,回调函数,MD5加密等

*/

request: function (url, opt_options) {

var xhr = this.getValidXHR();

//有可用连接

if(xhr) {

var me = this,

options     = opt_options || {},

data        = options.data || "",

async       = !(options.async === false),

username    = options.username || "",

password    = options.password || "",

method      = (options.method || "GET").toUpperCase(),

headers     = options.headers || {},

// 基本的逻辑来自lili同学提供的patch

timeout     = options.timeout || 0,

usemd5      = options.usemd5 || false,

tick, key, str,

stateChangeHandler = me.createStateChangeHandler();

// 将options参数中的事件参数复制到eventHandlers对象中

// 这里复制所有options的成员,eventHandlers有冗余

// 但是不会产生任何影响,并且代码紧凑

for(keyinoptions) {

xhr.eventHandlers[key] = options[key];

}

headers['X-Requested-With'] ='XMLHttpRequest';

try {

//提交到服务器端的参数是Map则转换为string

if(Object.prototype.toString.call(data)==='[object Object]'){

str = []

for(keyindata){

if(key){

str.push(encodeURIComponent(key) + '='+ encodeURIComponent(data[key]))

}

}

data = str.join('&');

}

//使用GET方式提交

if(method =='GET') {

if(data) {

url += (url.indexOf('?') >= 0 ? ( data.substr(0,1) =='&'?'':'&') :'?') + data;

data = null;

}

}

elseif(usemd5) {

data = me.encodeMD5(data);

}

if(username) {

xhr.open(method, url, async, username, password);

} else{

xhr.open(method, url, async);

}

if(async) {

xhr.onreadystatechange = stateChangeHandler;

}

// 在open之后再进行http请求头设定

// FIXME 是否需要添加; charset=UTF-8呢

if(method =='POST') {

xhr.setRequestHeader("Content-Type",

(headers['Content-Type'] ||"application/x-www-form-urlencoded"));

}

for(keyinheaders) {

if(headers.hasOwnProperty(key)) {

xhr.setRequestHeader(key, headers[key]);

}

}

xhr.fire('beforerequest');

if(timeout) {

xhr.tick = setTimeout(function(){

xhr.onreadystatechange = window.Requester.fn;

xhr.abort();

xhr.fire("timeout");

}, timeout);

}

xhr.send(data);

if(!xhr.eventHandlers['async']) {

stateChangeHandler();

}

} catch (ex) {

xhr.fire('failure');

}

}

//暂时没有可用连接,将请求放进队列

else{

this.que.push({'url':url,'options':options});

}

},

/

readyState发生变更时调用

@ignore

/

createStateChangeHandler: function() {

returnfunction() {

var xhr = this;

if(xhr.readyState == 4) {

try {

var stat = xhr.status;

} catch (ex) {

// 在请求时,如果网络中断,Firefox会无法取得status

xhr.fire('failure');

return;

}

xhr.fire(stat);

// http://www.never-online.net/blog/article.asp?id=261

// case12002: // Server timeout

// case12029: // dropped connections

// case12030: // dropped connections

// case12031: // dropped connections

// case12152: // closed by server

// case13030: // statusandstatusText are unavailable

// IE error sometimes returns 1223 whenit

// should be 204, so treat it as success

if((stat >= 200 && stat 

|| stat == 304

|| stat == 1223) {

xhr.fire('success');

} else{

xhr.fire('failure');

}

/

NOTE: Testing discovered that forsome bizarre reason, on Mozilla, the

JavaScript XmlHttpRequest.onreadystatechange handler

function maybe still be called after it is deleted. The theory is that the

callback is cached somewhere. Setting it to null oran empty function does

seem to work properly, though.

On IE, there are two problems: Setting onreadystatechange to null (as

opposed to an empty function) sometimes throws an exception. With

particular (rare) versions of jscript.dll, setting onreadystatechange from

within onreadystatechange causes a crash. Setting it from within a timeout

fixes this bug (see issue 1610).

End result: always set onreadystatechange to an empty function (never to

null). Never set onreadystatechange from within onreadystatechange (always

ina setTimeout()).

*/

window.setTimeout(function() {

// 避免内存泄露.

// 由newFunction改成不含此作用域链的 window.Requester.fn 函数,

// 以避免作用域链带来的隐性循环引用导致的IE下内存泄露. By rocy 2011-01-05 .

xhr.onreadystatechange = window.Requester.fn;

if(xhr.eventHandlers['async']) {

xhr = null;

}

}, 0);

window.Requester.checkQue();

}

}

},

/

* encodeMD5加密提交的数据

*

* @data{String} 需要加密的paramString

* @return{String} 加密后的paramString

*/

encodeMD5: function (data) {

var paramstr = Base64.encode(data).replace(/\+/g,'*');

var md5 = String(MD5.encode(paramstr)).toUpperCase();

paramstr = paramstr.split('');

paramstr.reverse();

return'result='+ md5 + paramstr.join('');

}

};

window.Requester = Requester;

window.Requester.fn = function(){};

/**

* 移除JSON字符串中多余的逗号如{'a':[',],}',],}

*

* @param{string} JSON字符串

* @return{string} 处理后的JSON字符串

*/

Requester.removeJSONExtComma = function(str) {

var i,

j,

len,

list,

c,

notValue = null,

preQuot = null,

lineNum;

list = String(str).split('');

for(i = 0, len = list.length; i 

c = list[i];

//单引或双引

if(/^[\'\"]$/.test(c)) {

if(notValue === null && preQuot === null) {

notValue = false;

preQuot = i;

continue;

}

//值

if(!notValue) {

//前面反斜杠个数

lineNum = 0;

for(j = i - 1; j > -1; j--) {

if(list[j] ==='\\') {lineNum++;}

else{ j = -1; }

}

//个数为偶数且和开始引号相同

//结束引号

if(lineNum % 2 === 0) {

if(list[preQuot] === c) {

notValue = true;

preQuot = -1;

}

}

}

//非值

else{

//开始引号

if(preQuot == -1) {

preQuot = i;

notValue = false;

}

//结束引号  

>> 留言评论

;