简单事情重复做,每天进步一点点
记录自己的学习过程。
XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。
所有现代浏览器 (IE7+、Firefox、Chrome、Safari 以及 Opera) 都内建了 XMLHttpRequest 对象。通过一行简单的 JavaScript 代码,我们就可以创建 XMLHttpRequest 对象。
const xhr = new XMLHttpRequest();
老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:
const xhr = new ActiveXObject("Microsoft.XMLHTTP");
使用xhr对象的时候,浏览器首先会检测原生的xhr是否存在,如果存在则返回它的新实例,如果原生对象不存在就检测ActiveX对象,如果都不存在,就抛出一个错误。
var xmlhttp=null;
if (window.XMLHttpRequest){ //code for all new browsers
xmlhttp=new XMLHttpRequest();
}else if (window.ActiveXObject){ //code for IE5 and IE6
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp!=null){
xmlhttp.onreadystatechange=state_Change; //监听请求状态
xmlhttp.open("GET",url,true); //初始化请求参数
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencode'); //设置请求头
xmlhttp.send(null); //发送请求
}else{
alert("Your browser does not support XMLHTTP.");
}
function state_Change(){
if (xmlhttp.readyState==4){// 4 = "loaded"
if (xmlhttp.status==200){// 200 = OK
// ...our code here...
}else{
alert("Problem retrieving XML data");
}
}
}
其中open()方法接收三个参数: 1、要发送的请求类型 GET || POST
2、请求的URL
3、是否异步请求 true || false
onreadystatechange 是一个事件句柄。它的值 (state_Change) 是一个函数的名称,当 XMLHttpRequest 对象的状态发生改变时,会触发此函数。状态从 0 (uninitialized) 到 4 (complete) 进行变化。仅在状态为 4 时,我们才执行代码。
abort(); //取消请求
XMLHttpRequest属性:
readyState: HTTP 请求的状态.当一个 XMLHttpRequest 初次创建时,这个属性的值从 0 开始,直到接收到完整的 HTTP 响应,这个值增加到 4。
0:未初始化,XMLHttpRequest 对象已创建,但尚未调用open()方法
1:启动,open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。
2:发送,Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3:接收,所有响应头部都已经接收到。响应体开始接收但未完成。
4:完成,HTTP 响应已经完全接收。
responseText: 响应体(不包括头部),如果还没有接收到数据的话,就是空字符串。如果 readyState 小于 3,这个属性就是一个空字符串。当 readyState 为 3,这个属性返回目前已经接收的响应部分。如果 readyState 为 4,这个属性保存了完整的响应体。
responseXML: 如果响应的内容类型是"text/xml"或者"application/xml",这个属性中将保存包含着响应数据的xml dom文档
status: 由服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 "Not Found" 错误。当 readyState 小于 3 的时候读取这一属性会导致一个异常。
statusText: http状态说明
以下是AXIOS请求的源码:
封装一个xhrAdapter方法,xhrAdapter方法接收一个config配置对象,并返回一个Promise
大致分为以下几个方面:
1、通过var request = new XMLHttpRequest()创建request对象
2、鉴权:if (config.auth) {...}, 判断config中是否携带auth参数
3、request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true)
调用open()方法来初始化请求参数,第一个参数是将所有的请求类型转换为大写,第二个参数构建url,第三个参数是否异步请求
4、request.onreadystatechange方法处理请求状态
5、if ('setRequestHeader' in request) { //此代码段添加请求头 }
6、if (config.cancelToken) { //此代码段取消请求 返回一个Promise }
7、最后调用send()方法发送请求
其它的就是一些异常错误处理,我们可以看到很多地方都会调用request = null,这个主要是在取消请求中使用,if (!request) {return;}请求不存在时就不会执行后面的代码。
完整代码:
function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var requestHeaders = config.headers;
if (utils.isFormData(requestData)) {
delete requestHeaders['Content-Type']; // Let the browser set it
}
var request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
var username = config.auth.username || '';
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
}
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// Set the request timeout in MS
request.timeout = config.timeout;
// Listen for ready state
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
return;
}
// Prepare the response
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
settle(resolve, reject, response);
// Clean up request
request = null;
};
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
// Clean up request
request = null;
};
// Handle low level network errors
request.onerror = function handleError() {
// Real errors are hidden from us by the browser
// onerror should only fire if it's a network error
reject(createError('Network Error', config, null, request));
// Clean up request
request = null;
};
// Handle timeout
request.ontimeout = function handleTimeout() {
var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
request));
// Clean up request
request = null;
};
// Add xsrf header
// This is only done if running in a standard browser environment.
// Specifically not if we're in a web worker, or react-native.
if (utils.isStandardBrowserEnv()) {
// Add xsrf header
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
cookies.read(config.xsrfCookieName) :
undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
}
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
// Remove Content-Type if data is undefined
delete requestHeaders[key];
} else {
// Otherwise add header to the request
request.setRequestHeader(key, val);
}
});
}
// Add withCredentials to request if needed
if (!utils.isUndefined(config.withCredentials)) {
request.withCredentials = !!config.withCredentials;
}
// Add responseType to request if needed
if (config.responseType) {
try {
request.responseType = config.responseType;
} catch (e) {
// Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
// But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
if (config.responseType !== 'json') {
throw e;
}
}
}
// Handle progress if needed
if (typeof config.onDownloadProgress === 'function') {
request.addEventListener('progress', config.onDownloadProgress);
}
// Not all browsers support upload events
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
if (!requestData) {
requestData = null;
}
// Send the request
request.send(requestData);
});
}