/** * 转换当前地址为字符串。 */ toString() { let auth = this.auth || ""; if (auth) { auth = encodeURIComponent(auth).replace(/%3A/g, ":"); auth += "@"; } let protocol = this.protocol || ""; let pathname = this.pathname || ""; let hash = this.hash || ""; let host: string | undefined; let query = ""; if (this.host) { host = auth + this.host; } else if (this.hostname) { host = auth + (this.hostname.indexOf(":") === -1 ? this.hostname : "[" + this.hostname + "]"); if (this.port) { host += ":" + this.port; } } if (this.query !== null && typeof this.query === "object") query = formatQuery(this.query); let search = this.search || (query && ("?" + query)) || ""; if (protocol && protocol.charCodeAt(protocol.length - 1) !== 58/*:*/) protocol += ":"; let newPathname = ""; let lastPos = 0; for (let i = 0; i < pathname.length; ++i) { switch (pathname.charCodeAt(i)) { case 35: // '#' if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += "%23"; lastPos = i + 1; break; case 63: // '?' if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += "%3F"; lastPos = i + 1; break; } } if (lastPos > 0) { if (lastPos !== pathname.length) pathname = newPathname + pathname.slice(lastPos); else pathname = newPathname; } // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. if (this.slashes || (!protocol || slashedProtocol[protocol]) && host !== undefined) { host = "//" + (host || ""); if (pathname && pathname.charCodeAt(0) !== 47/*/*/) pathname = "/" + pathname; } else if (!host) { host = ""; } search = search.replace("#", "%23"); if (hash && hash.charCodeAt(0) !== 35/*#*/) hash = "#" + hash; if (search && search.charCodeAt(0) !== 63/*?*/) search = "?" + search; return protocol + host + pathname + search + hash; }
/** * 发送当前的请求。 * @return 如果请求发送成功则返回 true,否则返回 false。 */ send() { // 设置属性默认值。 this.type = this.type || "GET"; this.url = this.url || location.href; if (this.data != null && !(this.data instanceof FormData)) { this.contentType = this.contentType || "application/x-www-form-urlencoded"; if (typeof this.data === "object") { this.data = this.contentType === "application/json" && this.type !== "GET" ? JSON.stringify(this.data) : formatQuery(this.data); } if (this.type === "GET") { this.url += (this.url.indexOf("?") >= 0 ? "&" : "?") + this.data; this.data = null; } } this.async = this.async !== false; // 准备请求。 const xhr = this.xhr = new XMLHttpRequest(); const end: Ajax["_end"] = this._end = (message, inerternalError) => { try { // 不重复执行回调。 // 忽略 onreadystatechange 最后一次之前的调用。 if (!this._end || (!inerternalError && xhr.readyState !== 4)) { return; } delete this._end; // 删除 readystatechange 。 xhr.onreadystatechange = null!; // 判断是否存在错误。 if (inerternalError) { this.status = inerternalError; // 手动中止请求。 if (xhr.readyState !== 4) { xhr.abort(); } } else { this.status = xhr.status; try { this.statusText = xhr.statusText; } catch (firefoxCrossDomainError) { // 如果跨域,火狐会报错。 this.statusText = ""; } if (checkStatus(this.status)) { try { this.responseText = xhr.responseText; } catch (ieResponseTextError) { // IE6-9:请求二进制格式的文件报错。 this.responseText = ""; } message = null; } else { message = this.status + ": " + this.statusText; } } } catch (firefoxAccessError) { return end(firefoxAccessError, -5); } // 执行用户回调。 if (message) { this.error && this.error(message, this); } else { this.success && this.success(this.responseText, this); } this.complete && this.complete(message, this); }; // 发送请求。 try { if (this.username) { xhr.open(this.type, this.url, this.async, this.username, this.password); } else { xhr.open(this.type, this.url, this.async); } } catch (ieOpenError) { // IE: 地址错误时可能产生异常。 end(ieOpenError, -3); return false; } for (const header in this.headers) { try { xhr.setRequestHeader(header, this.headers[header]); } catch (firefoxSetHeaderError) { // FF: 跨域时设置头可能产生异常。 } } if (this.contentType) { try { xhr.setRequestHeader("Content-Type", this.contentType); } catch (firefoxSetHeaderError) { // FF: 跨域时设置头可能产生异常。 } } if (this.withCredentials) { xhr.withCredentials = true; } try { xhr.send(this.data); } catch (sendError) { // 地址错误时产生异常 。 end(sendError, -4); return false; } // 同步时火狐不会自动调用 onreadystatechange if (!this.async) { end(null, 0); return true; } // 绑定 onreadystatechange, 让 xhr 根据请求情况调用 done。 xhr.onreadystatechange = end as any; if (this.timeout >= 0) { setTimeout(() => { end("Timeout", -2); }, this.timeout); } return true; }