1 /** 2 * @fileOverview encapsulation of io object . as transaction object in yui3 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("ajax/XhrObject", function (S, undefined) { 6 7 var OK_CODE = 200, 8 Promise = S.Promise, 9 MULTIPLE_CHOICES = 300, 10 NOT_MODIFIED = 304, 11 // get individual response header from responseheader str 12 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg; 13 14 function handleResponseData(xhrObject) { 15 16 // text xml 是否原生转化支持 17 var text = xhrObject.responseText, 18 xml = xhrObject.responseXML, 19 c = xhrObject.config, 20 cConverts = c.converters, 21 xConverts = xhrObject.converters || {}, 22 type, 23 responseData, 24 contents = c.contents, 25 dataType = c.dataType; 26 27 // 例如 script 直接是js引擎执行,没有返回值,不需要自己处理初始返回值 28 // jsonp 时还需要把 script 转换成 json,后面还得自己来 29 if (text || xml) { 30 31 var contentType = xhrObject.mimeType || xhrObject.getResponseHeader("Content-Type"); 32 33 // 去除无用的通用格式 34 while (dataType[0] == "*") { 35 dataType.shift(); 36 } 37 38 if (!dataType.length) { 39 // 获取源数据格式,放在第一个 40 for (type in contents) { 41 if (contents[type].test(contentType)) { 42 if (dataType[0] != type) { 43 dataType.unshift(type); 44 } 45 break; 46 } 47 } 48 } 49 // 服务器端没有告知(并且客户端没有 mimetype )默认 text 类型 50 dataType[0] = dataType[0] || "text"; 51 52 //获得合适的初始数据 53 if (dataType[0] == "text" && text !== undefined) { 54 responseData = text; 55 } 56 // 有 xml 值才直接取,否则可能还要从 xml 转 57 else if (dataType[0] == "xml" && xml !== undefined) { 58 responseData = xml; 59 } else { 60 var rawData = {text:text, xml:xml}; 61 // 看能否从 text xml 转换到合适数据,并设置起始类型为 text/xml 62 S.each(["text", "xml"], function (prevType) { 63 var type = dataType[0], 64 converter = xConverts[prevType] && xConverts[prevType][type] || 65 cConverts[prevType] && cConverts[prevType][type]; 66 if (converter && rawData[prevType]) { 67 dataType.unshift(prevType); 68 responseData = prevType == "text" ? text : xml; 69 return false; 70 } 71 }); 72 } 73 } 74 var prevType = dataType[0]; 75 76 // 按照转化链把初始数据转换成我们想要的数据类型 77 for (var i = 1; i < dataType.length; i++) { 78 type = dataType[i]; 79 80 var converter = xConverts[prevType] && xConverts[prevType][type] || 81 cConverts[prevType] && cConverts[prevType][type]; 82 83 if (!converter) { 84 throw "no covert for " + prevType + " => " + type; 85 } 86 responseData = converter(responseData); 87 88 prevType = type; 89 } 90 91 xhrObject.responseData = responseData; 92 } 93 94 /** 95 * @class A class for constructing io request instances. !Do Not New By Yourself! 96 * @extends KISSY.Promise 97 * @memberOf IO 98 */ 99 function XhrObject(c) { 100 Promise.call(this); 101 S.mix(this, { 102 // 结构化数据,如 json 103 responseData:null, 104 config:c || {}, 105 timeoutTimer:null, 106 107 /** 108 * @field 109 * @memberOf IO.XhrObject# 110 * @description String typed data returned from server 111 */ 112 responseText:null, 113 /** 114 * @field 115 * @memberOf IO.XhrObject# 116 * @description xml typed data returned from server 117 */ 118 responseXML:null, 119 responseHeadersString:"", 120 responseHeaders:null, 121 requestHeaders:{}, 122 /** 123 * @field 124 * @memberOf IO.XhrObject# 125 * @description <br> 126 * readyState of current request<br> 127 * 0: initialized<br> 128 * 1: send <br> 129 * 4: completed<br> 130 */ 131 readyState:0, 132 state:0, 133 /** 134 * @field 135 * @memberOf IO.XhrObject# 136 * @description HTTP statusText of current request 137 */ 138 statusText:null, 139 /** 140 * @field 141 * @memberOf IO.XhrObject# 142 * @description <br> HTTP Status Code of current request <br> 143 * eg:<br> 144 * 200 : ok<br> 145 * 404 : Not Found<br> 146 * 500 : Server Error<br> 147 */ 148 status:0, 149 transport:null, 150 _defer:new S.Defer(this) 151 }); 152 } 153 154 S.extend(XhrObject, Promise, 155 /** 156 * @lends IO.XhrObject.prototype 157 */ 158 { 159 // Caches the header 160 setRequestHeader:function (name, value) { 161 var self = this; 162 self.requestHeaders[ name ] = value; 163 return self; 164 }, 165 166 /** 167 * get all response headers as string after request is completed 168 * @returns {String} 169 */ 170 getAllResponseHeaders:function () { 171 var self = this; 172 return self.state === 2 ? self.responseHeadersString : null; 173 }, 174 175 /** 176 * get header value in response to specified header name 177 * @param {String} name header name 178 * @return {String} header value 179 */ 180 getResponseHeader:function (name) { 181 var match, self = this; 182 if (self.state === 2) { 183 if (!self.responseHeaders) { 184 self.responseHeaders = {}; 185 while (( match = rheaders.exec(self.responseHeadersString) )) { 186 self.responseHeaders[ match[1] ] = match[ 2 ]; 187 } 188 } 189 match = self.responseHeaders[ name ]; 190 } 191 return match === undefined ? null : match; 192 }, 193 194 // Overrides response content-type header 195 overrideMimeType:function (type) { 196 var self = this; 197 if (!self.state) { 198 self.mimeType = type; 199 } 200 return self; 201 }, 202 203 /** 204 * cancel this request 205 * @param {String} [statusText=abort] error reason as current request object's statusText 206 */ 207 abort:function (statusText) { 208 var self = this; 209 statusText = statusText || "abort"; 210 if (self.transport) { 211 self.transport.abort(statusText); 212 } 213 self._xhrReady(0, statusText); 214 return self; 215 }, 216 217 /** 218 * get native XMLHttpRequest 219 * @since 1.3 220 */ 221 getNativeXhr:function () { 222 var transport; 223 if (transport = this.transport) { 224 return transport.nativeXhr; 225 } 226 }, 227 228 _xhrReady:function (status, statusText) { 229 var self = this; 230 // 只能执行一次,防止重复执行 231 // 例如完成后,调用 abort 232 233 // 到这要么成功,调用success 234 // 要么失败,调用 error 235 // 最终都会调用 complete 236 if (self.state == 2) { 237 return; 238 } 239 self.state = 2; 240 self.readyState = 4; 241 var isSuccess; 242 if (status >= OK_CODE && status < MULTIPLE_CHOICES || status == NOT_MODIFIED) { 243 244 if (status == NOT_MODIFIED) { 245 statusText = "notmodified"; 246 isSuccess = true; 247 } else { 248 try { 249 handleResponseData(self); 250 statusText = "success"; 251 isSuccess = true; 252 } catch (e) { 253 statusText = "parsererror : " + e; 254 } 255 } 256 257 } else { 258 if (status < 0) { 259 status = 0; 260 } 261 } 262 263 self.status = status; 264 self.statusText = statusText; 265 266 var defer = self._defer; 267 defer[isSuccess ? "resolve" : "reject"]([self.responseData, self.statusText, self]); 268 } 269 } 270 ); 271 272 return XhrObject; 273 });