1 /** 2 * @fileOverview base for xhr and subdomain 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("ajax/XhrTransportBase", function (S, io) { 6 var OK_CODE = 200, 7 win = S.Env.host, 8 // http://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx 9 _XDomainRequest = win['XDomainRequest'], 10 NO_CONTENT_CODE = 204, 11 NOT_FOUND_CODE = 404, 12 NO_CONTENT_CODE2 = 1223, 13 XhrTransportBase = { 14 proto:{} 15 }; 16 17 function createStandardXHR(_, refWin) { 18 try { 19 return new (refWin || win)['XMLHttpRequest'](); 20 } catch (e) { 21 //S.log("createStandardXHR error"); 22 } 23 return undefined; 24 } 25 26 function createActiveXHR(_, refWin) { 27 try { 28 return new (refWin || win)['ActiveXObject']("Microsoft.XMLHTTP"); 29 } catch (e) { 30 S.log("createActiveXHR error"); 31 } 32 return undefined; 33 } 34 35 XhrTransportBase.nativeXhr = win['ActiveXObject'] ? function (crossDomain, refWin) { 36 if (crossDomain && _XDomainRequest) { 37 return new _XDomainRequest(); 38 } 39 // ie7 XMLHttpRequest 不能访问本地文件 40 return !io.isLocal && createStandardXHR(crossDomain, refWin) || createActiveXHR(crossDomain, refWin); 41 } : createStandardXHR; 42 43 function isInstanceOfXDomainRequest(xhr) { 44 return _XDomainRequest && (xhr instanceof _XDomainRequest); 45 } 46 47 S.mix(XhrTransportBase.proto, { 48 sendInternal:function () { 49 50 var self = this, 51 xhrObj = self.xhrObj, 52 c = xhrObj.config; 53 54 var nativeXhr = self.nativeXhr, 55 xhrFields, 56 i; 57 58 if (c['username']) { 59 nativeXhr.open(c.type, c.url, c.async, c['username'], c.password) 60 } else { 61 nativeXhr.open(c.type, c.url, c.async); 62 } 63 64 if (xhrFields = c['xhrFields']) { 65 for (i in xhrFields) { 66 if (xhrFields.hasOwnProperty(i)) { 67 nativeXhr[ i ] = xhrFields[ i ]; 68 } 69 } 70 } 71 72 // Override mime type if supported 73 if (xhrObj.mimeType && nativeXhr.overrideMimeType) { 74 nativeXhr.overrideMimeType(xhrObj.mimeType); 75 } 76 // yui3 and jquery both have 77 if (!c.crossDomain && !xhrObj.requestHeaders["X-Requested-With"]) { 78 xhrObj.requestHeaders[ "X-Requested-With" ] = "XMLHttpRequest"; 79 } 80 try { 81 // 跨域时,不能设,否则请求变成 82 // OPTIONS /xhr/r.php HTTP/1.1 83 if (!c.crossDomain) { 84 for (i in xhrObj.requestHeaders) { 85 nativeXhr.setRequestHeader(i, xhrObj.requestHeaders[ i ]); 86 } 87 } 88 } catch (e) { 89 S.log("setRequestHeader in xhr error : "); 90 S.log(e); 91 } 92 93 nativeXhr.send(c.hasContent && c.data || null); 94 95 if (!c.async || nativeXhr.readyState == 4) { 96 self._callback(); 97 } else { 98 // _XDomainRequest 单独的回调机制 99 if (isInstanceOfXDomainRequest(nativeXhr)) { 100 nativeXhr.onload = function () { 101 nativeXhr.readyState = 4; 102 nativeXhr.status = 200; 103 self._callback(); 104 }; 105 nativeXhr.onerror = function () { 106 nativeXhr.readyState = 4; 107 nativeXhr.status = 500; 108 self._callback(); 109 }; 110 } else { 111 nativeXhr.onreadystatechange = function () { 112 self._callback(); 113 }; 114 } 115 } 116 }, 117 // 由 xhrObj.abort 调用,自己不可以调用 xhrObj.abort 118 abort:function () { 119 this._callback(0, 1); 120 }, 121 122 _callback:function (event, abort) { 123 // Firefox throws exceptions when accessing properties 124 // of an xhr when a network error occured 125 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) 126 try { 127 var self = this, 128 nativeXhr = self.nativeXhr, 129 xhrObj = self.xhrObj, 130 c = xhrObj.config; 131 //abort or complete 132 if (abort || nativeXhr.readyState == 4) { 133 134 // ie6 ActiveObject 设置不恰当属性导致出错 135 if (isInstanceOfXDomainRequest(nativeXhr)) { 136 nativeXhr.onerror = S.noop; 137 nativeXhr.onload = S.noop; 138 } else { 139 // ie6 ActiveObject 只能设置,不能读取这个属性,否则出错! 140 nativeXhr.onreadystatechange = S.noop; 141 } 142 143 if (abort) { 144 // 完成以后 abort 不要调用 145 if (nativeXhr.readyState !== 4) { 146 nativeXhr.abort(); 147 } 148 } else { 149 var status = nativeXhr.status; 150 151 // _XDomainRequest 不能获取响应头 152 if (!isInstanceOfXDomainRequest(nativeXhr)) { 153 xhrObj.responseHeadersString = nativeXhr.getAllResponseHeaders(); 154 } 155 156 var xml = nativeXhr.responseXML; 157 158 // Construct response list 159 if (xml && xml.documentElement /* #4958 */) { 160 xhrObj.responseXML = xml; 161 } 162 xhrObj.responseText = nativeXhr.responseText; 163 164 // Firefox throws an exception when accessing 165 // statusText for faulty cross-domain requests 166 try { 167 var statusText = nativeXhr.statusText; 168 } catch (e) { 169 S.log("xhr statustext error : "); 170 S.log(e); 171 // We normalize with Webkit giving an empty statusText 172 statusText = ""; 173 } 174 175 // Filter status for non standard behaviors 176 // If the request is local and we have data: assume a success 177 // (success with no data won't get notified, that's the best we 178 // can do given current implementations) 179 if (!status && io.isLocal && !c.crossDomain) { 180 status = xhrObj.responseText ? OK_CODE : NOT_FOUND_CODE; 181 // IE - #1450: sometimes returns 1223 when it should be 204 182 } else if (status === NO_CONTENT_CODE2) { 183 status = NO_CONTENT_CODE; 184 } 185 186 xhrObj._xhrReady(status, statusText); 187 } 188 } 189 } catch (firefoxAccessException) { 190 nativeXhr.onreadystatechange = S.noop; 191 if (!abort) { 192 xhrObj._xhrReady(-1, firefoxAccessException); 193 } 194 } 195 } 196 }); 197 198 return XhrTransportBase; 199 }, { 200 requires:['./base'] 201 });