axios瀏覽器異步請求方法封裝 XMLHttpRequest


axios學習筆記defaults(瀏覽器端異步請求處理方式)

瀏覽器異步請求方法封裝,主要使用XMLHttpRequest

lib/adapters/xhr.js

//入口
var utils = require('./../utils');
var settle = require('./../core/settle');
var buildURL = require('./../heapers/buildURL');
var buildFullPath = require('./../core/buildFullPath');
var parseHeaders = require('./../heapers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var createError = require('./../core/createError')

settle方法

lib/core/settle.js

//驗證請求返回結果,成功走resolve,失敗走reject
var createError = require('./createError')
function seetle(resolve, reject, response){//resolve,reject為promise中參數
	var validateStatus = response.config.validateStatus;//獲取默認的狀態碼校驗方法
	//狀態碼驗證通過
	if(!validateStatus || validateStatus(response.staus)){
		resolve(data)
	} else {
		reject(createError(
			'request failed with status code' + response.status,//響應狀態碼
			response.config,//響應配置項
			null,
			response.request,
			response,
		))
	}
}

createError方法

lib/core/createError.js

//new一個包含message的error對象
var enhanceError = require('./enchanceError')
function createError(message, config, code, request, response){
	var error = new Error(message);//實例化一個error對象
	//給error對象添加請求的各種信息
	return enhanceError(error, config, code, request, response)
}

enchanceError方法

lib/core/enhanceError.js

//將請求出錯返回的相關信息全都掛到error對象上,然后拋出,方便定位出錯信息
function enchanceRrror(error, config, code, request, response){
	error.config = config;
	if(code){
		error.code = code
	}
	error.request = request;
	error.response = response;
	error.isAxiosError = true;
	return error.toJSON = function(){
		return {
			// Standard(標准瀏覽器)
			message: this.message,
			name: this.name,
			// Microsoft(ie可用)
		    description: this.description,
		    number: this.number,
		    // Mozilla(火狐)
		    fileName: this.fileName,
		    lineNumber: this.lineNumber,
		    columnNumber: this.columnNumber,
		    stack: this.stack,
		    // Axios
		    config: this.config,
		    code: this.code
		}
	}
	return error
}

buildURL方法

lib/heapers/buildURL.js

//綁定get請求中的parmas到url上
function bindURL(url, params, paramsSerializer) {
	if(!params) return url;
	var serializedParams;
	if(paramsSerialized) {
		serializedParams = paramsSerializer(params);
	} else if(utils.isURLSerarchParams(params)) {
		serializedParams = params.toString();
	} else {
		var pats = [];
		utils.forEach(params, function serialze(val, key) {
			if(val == null || typeof val == 'undefind'){
				return;
			}
			//將val變成數組
			if(utils.isArray(val)){
				key = key+'[]';
			}else{
				val = [val];
			}
		})
		utils.forEach(val, function parseValue(v) {
	        if (utils.isDate(v)) {
	          v = v.toISOString();
	        } else if (utils.isObject(v)) {
	          v = JSON.stringify(v);
	        }
        	parts.push(encode(key) + '=' + encode(v));
      	});
      	serializedParams = pats.join(&);
	}
	if(serializedParams) {
		var hashmarkIndex = url.indexOf('#');
		if(hashmarkIndex != -1) {
			url = url.slice(0, hashmarkIndex);
		}
		url += (url.indexOf('?') == -1? '?' : '&') + serializedParams;
	}
	return url;
}

buildFullPath

lib/core/buildFullPath.js

//獲得完整的url
function buildFullPath(baseUrl, requestUrl) {
	//存在baseUrl 且requestUrl不是完整的url
	if(baseUrl && !isAbsoluteURL(requestUrl)){
		//合並url
		return combine(baseUrl, requestUrl)
	}
	return requestUrl;
}

xhrAdapter方法

lib/adapter/xhr.js

//瀏覽器異步請求基本適配器
function xhrAdapter(config) {
	return new Promise(fuction dispatchXhrRequest(resove, reject){
		var requestData = config.data;
		var requestHeaders = config.headers;
		//如果請求參數是formData類型, 刪除用戶自定義的請求參數格式Content-Type
		if(utils.isFormData(requestData)){
			delete requestHedeaders['Content-Type'];
		}
		//XMLHttpRequest 對象用戶與后台服務器交換數據,所有現代瀏覽器都支持此對象
		var request = new XMLHttpRequest()
		//加auth信息
		if(config.auth){
			var username = config.auth.username || '';
			var password = config.auth.password || '';
			requestHeaders.Authorization = 'Basic' + btoa(username + ':' + password);
		}
		var fullPath = buildFullUrl(config.baseURL, config.url);
		request.open(config.methods.toUpperCase, buildUrl(fullPath, config.params, config.paramsSerialze), true);
		request.timeout = config.timeout;

		request.onreadystatechange = function handleload() {
			if(!request || request.readyState !== 4) {
				return null;
			}
			if(request.status == 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)){
				return null;
			}
			//獲取所有請求頭信息
			var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(requerst.getAllResponseHeaders()) : null;
			//如果接受數據類型為text類型,返回responseText 否則返回request.response
			var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
			var response = {
				data: responseData,
				status: request.status,//響應中數字狀態碼,請求完成前status為0.如果XMLHttpRequest出錯也為0
				statusText: request.statusText,
				config: config,
				request: request,
			}
			//結果自定義驗證
			settle(resolve, reject, response)
			//清除 request
			request = null;
		}

        //請求被中止時處理
        request.onabort = function handleAbort() {
        	if(!request) return;
        	reject(createError('Request Abort', config, 'ECONNABORTED', request))
        	request = null;
        }

		request.onerror = function handleError() {
			reject(createError('Network Error', config, null, request))
			//清除請求實例
			request = null  
		}

		request.ontimeout = function handleTimeout() {
			var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
			if(config.timeoutErrorMessage) {
				timeoutErrorMessage = config.timeoutErrorMessage
			}
			reject(createError(timeoutErrorMessage, config, 'ECONNABORTED', request))
			request = null
		}

		<!-- 現代瀏覽器添加xsrfValue -->
		if(utils.isStandarBrowserEvn()){
			<!-- cookeis中有3個方法,write read remove 寫 讀 刪除 -->
			var cookies = requset('./../headers/cookies');
			var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? cookie.read(config.xsrfCookieName) : undefined;
			<!-- 將xsrfCookieName寫道請求頭里面 -->
			if(xsrfValue) {
				requestHeaders[config.xsrfCookieName] = xsrfValue;
			}
		}

		<!-- add heders to the request -->
		if('setReuqetHeaders' in request) {
			utils.forEach(requestHeaders, function setRequestHeader(val, key) {
				//如果沒有參數,content-type 不需要設置
				if(typeof requestData === 'undefined' && key.toLowerCase()=='content-type'){
					delete requestHeaders[key];
				} else {
					request.setRequestHeaders(key, val);
				}
			})
		}

		<!-- 設置跨域請求的withCredentials 指定跨域Access-Control請求是否應該帶有授權信息 例如cookie或者authorization頭 -->
		if(config.withCredentials) {
			request.withCredentials = true;
		}
		<!-- 設置瀏覽器期望接受返回數據的類型 對應resposne中的Content-Type-->
		if(config.responseType) {
			try {
				request.responseType = config.responseType
			} catch (e) {
				if(config.responseType !== 'json') {
					throw e;
				}
			}
		}
		<!-- 處理進度。例如下載文件需要 監聽進度事件-->
		if(typeof config.onDownloadProgress === 'function') {
			request.addEventListenner('progress', config.onDownloadProgress)
		}
		<!-- 不是所有的的瀏覽器都支持上傳事件 upload -->
		if(typeof config.onUploadProgress == 'function' && request.upload){
			request.addEventListenner('progress', config.onUploadProgress)
		}
		<!-- cancleToken axios中取消請求 -->
		if(config.cancleToken){
			//如果請求返回成功,則打斷request
			config.cancleToken.promise.then(function onCancled(cancale){
				if(!request) return;
				request.abort(); 打斷已經發出的請求
				reject(cancle)
				request = null
			})
		}
		if(requestData === undefined){
			requestData = null;
		}
		//發送數據
		rquest.send(requestData)

	})
}

總結

request 實例上的方法和事件 var request = new XMLHttpRequest();

方法

request.abort() 如果請求已被發送,則立刻中止請求
request.getAllResponseHeaders() 以字符串的形式返回所有用CRLF分割的響應頭,如果沒有收到響應,則返回null
request.getResponseHeaders() 返回包含指定響應頭的字符串,如果響應頭沒收到或者不存在該報頭,則返回null
request.open() 初始化一個請求,該方法只能再javascript中使用,若在native code 中初始化請求,請使用openRequest()
request.overrideMimeType() 重寫服務器返回的MIME類型
request.send() 發送請求,如果請求時異步的,那么該放大將在請求發送后立即返回
request.setRequestHeader() 設置http請求頭,必須在open()之后send()之前調用setRequestHeader()方法

事件

abort 也可以使用onabort屬性 當request被停止時觸發
error 也可以使用onerror屬性 當request遇到錯誤時觸發
load 也可以使用onload屬性 當request請求完成時觸發
timeout 也可以使用ontimeout屬性 預設時間內沒有接受到響應時觸發
progress 進度事件 request.addEventListener('progress', function(e) {})
...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM