前端常見面試-請求篇

        對於前端來講,請求是前端平常工做必備的,經過請求才能與後端進行數據交互,尤爲在如今先後端分離的開發模式下,請求顯得就更加劇要。所以,對於前端開發者來講,掌握請求就很重要。下面將從http請求和常見的幾個請求技術作具體的講解css

1、XMLHttpRequest

        XMLHttpRequest一開始只是微軟瀏覽器提供的一個接口,後來各大瀏覽器紛紛效仿也提供了這個接口,再後來W3C對它進行了標準化,按照標準先後能夠分爲兩個版本,具體闡述以下:html

版本以(老版本):
//新建一個XMLHttpRequest對象
var xhr=new XMLHttpRequest();

//進行請求
xhr.open('GET', 'url');
xhr.send();

//等待服務器響應
xhr.onreadystatechange = function(){
    //該函數會被調用四次,所以須要判斷狀態是否爲4
    if ( xhr.readyState == 4 && xhr.status == 200 ) {
      alert( xhr.responseText );

    } else {

      alert( xhr.statusText );

    }
};

        在老版本中的,對應的具體屬性說明以下:前端

  1. xhr.readyState:XMLHttpRequest對象的狀態,等於4表示數據已經接收完畢。
  2. xhr.status:服務器返回的狀態碼,等於200表示一切正常。
  3. xhr.responseText:服務器返回的文本數據
  4. xhr.responseXML:服務器返回的XML格式的數據
  5. xhr.statusText:服務器返回的狀態文本。

        老版本由於不是統一的標準,各個瀏覽器廠商在實現的時候都有必定的差別,並且在存在一些缺陷:vue

  1. 只支持文本數據的傳送,沒法用來讀取和上傳二進制文件。
  2. 傳送和接收數據時,沒有進度信息,只能提示有沒有完成。
  3. 受到"同域限制"(Same Origin Policy),只能向同一域名的服務器請求數據。
版本二(標準後的版本):

        爲了更好的使用XMLHttpRequest,w3school發佈了標準版本,該版本彌補了版本一的缺陷,也被各大瀏覽器廠商接受並實現。具體爲:node

  1. 能夠設置HTTP請求的時限。
  2. 可使用FormData對象管理表單數據。
  3. 能夠上傳文件。
  4. 能夠請求不一樣域名下的數據(跨域請求)。
  5. 能夠獲取服務器端的二進制數據。
  6. 能夠得到數據傳輸的進度信息。

固然,通常爲了友好的進行兼容各個瀏覽器,會採用對瀏覽器進行判斷並進行兼容性模式來獲取XMLHttpRequest的對象jquery

var xhr;
if (window.XMLHttpRequest) { // Mozilla, Safari...
  xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
 try {
    xhr = new ActiveXObject('Msxml2.XMLHTTP');
 } catch (e) {
 try {
      xhr = new ActiveXObject('Microsoft.XMLHTTP'); //IE5,6
 } catch (e) {}
 }
}
// 請求成功回調函數
xhr.onload = e => {
    console.log('request success');
};
// 請求結束
xhr.onloadend = e => {
    console.log('request loadend');
};
// 請求出錯
xhr.onerror = e => {
    console.log('request error');
};
// 請求超時
xhr.ontimeout = e => {
    console.log('request timeout');
};
// 請求回調函數.XMLHttpRequest標準又分爲Level 1和Level 2,這是Level 1和的回調處理方式
// xhr.onreadystatechange = () => {
//  if (xhr.readyState !== 4) {
//  return;
//  }
//  const status = xhr.status;
//  if ((status >= 200 && status < 300) || status === 304) {
//  console.log('request success');
//  } else {
//  console.log('request error');
//  }
//  };

xhr.timeout = 0; // 設置超時時間,0表示永不超時
// 初始化請求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 設置指望的返回數據類型 'json' 'text' 'document' ...
xhr.responseType = '';
// 設置請求頭
xhr.setRequestHeader('', '');
// 發送請求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

2、ajax請求

        AJAX 是一種與服務器交換數據的技術,能夠在不從新載入整個頁面的狀況下更新網頁的一部分,其實就是對XMLHttpRequest的封裝,能夠直接引入jquery工具包來進行調用ajax請求(jquery是一個js工具包,其特色是:寫得少,作得多),具體的ajax經常使用方式以下:ios

方法 描述
$.ajax() 執行異步 AJAX 請求
$.ajaxPrefilter() 在每一個請求發送以前且被 $.ajax() 處理以前,處理自定義 Ajax 選項或修改已存在選項
$.ajaxSetup() 爲未來的 AJAX 請求設置默認值
$.ajaxTransport() 建立處理 Ajax 數據實際傳送的對象
$.get() 使用 AJAX 的 HTTP GET 請求從服務器加載數據
$.getJSON() 使用 HTTP GET 請求從服務器加載 JSON 編碼的數據
$.getScript() 使用 AJAX 的 HTTP GET 請求從服務器加載並執行 JavaScript
$.param() 建立數組或對象的序列化表示形式(可用於 AJAX 請求的 URL 查詢字符串)
$.post() 使用 AJAX 的 HTTP POST 請求從服務器加載數據
ajaxComplete() 規定 AJAX 請求完成時運行的函數
ajaxError() 規定 AJAX 請求失敗時運行的函數
ajaxSend() 規定 AJAX 請求發送以前運行的函數
ajaxStart() 規定第一個 AJAX 請求開始時運行的函數
ajaxStop() 規定全部的 AJAX 請求完成時運行的函數
ajaxSuccess() 規定 AJAX 請求成功完成時運行的函數
load() 從服務器加載數據,並把返回的數據放置到指定的元素中
serialize() 編碼表單元素集爲字符串以便提交
serializeArray() 編碼表單元素集爲 names 和 values 的數組
優勢:
  • 對原生XHR的封裝
  • 針對MVC的編程
  • 完美的兼容性
  • 支持jsonp
缺點:
  • 不符合MVVM
  • 異步模型不夠現代,不支持鏈式,代碼可讀性差
  • 整個Jquery太大,引入成本太高

        固然,咱們能夠直接使用XMLHttpReqeust來進行實現本身的ajax封裝,具體代碼以下:es6

const http = {
  /**
   * js封裝ajax請求
   * >>使用new XMLHttpRequest 建立請求對象,因此不考慮低端IE瀏覽器(IE6及如下不支持XMLHttpRequest)
   * >>使用es6語法,若是須要在正式環境使用,則能夠用babel轉換爲es5語法 https://babeljs.cn/docs/setup/#installation
   *  @param settings 請求參數模仿jQuery ajax
   *  調用該方法,data參數須要和請求頭Content-Type對應
   *  Content-Type                        data                                     描述
   *  application/x-www-form-urlencoded   'name=哈哈&age=12'或{name:'哈哈',age:12}  查詢字符串,用&分割
   *  application/json                     name=哈哈&age=12'                        json字符串
   *  multipart/form-data                  new FormData()                           FormData對象,當爲FormData類型,不要手動設置Content-Type
   *  注意:請求參數若是包含日期類型.是否能請求成功須要後臺接口配合
   */
  ajax: (settings = {}) => {
    // 初始化請求參數
    let _s = Object.assign({
      url: '', // string
      type: 'GET', // string 'GET' 'POST' 'DELETE'
      dataType: 'json', // string 指望的返回數據類型:'json' 'text' 'document' ...
      async: true, //  boolean true:異步請求 false:同步請求 required
      data: null, // any 請求參數,data須要和請求頭Content-Type對應
      headers: {}, // object 請求頭
      timeout: 1000, // string 超時時間:0表示不設置超時
      beforeSend: (xhr) => {
      },
      success: (result, status, xhr) => {
      },
      error: (xhr, status, error) => {
      },
      complete: (xhr, status) => {
      }
    }, settings);
    // 參數驗證
    if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
      alert('參數有誤');
      return;
    }
    // 建立XMLHttpRequest請求對象
    let xhr = new XMLHttpRequest();
    // 請求開始回調函數
    xhr.addEventListener('loadstart', e => {
      _s.beforeSend(xhr);
    });
    // 請求成功回調函數
    xhr.addEventListener('load', e => {
      const status = xhr.status;
      if ((status >= 200 && status < 300) || status === 304) {
        let result;
        if (xhr.responseType === 'text') {
          result = xhr.responseText;
        } else if (xhr.responseType === 'document') {
          result = xhr.responseXML;
        } else {
          result = xhr.response;
        }
        // 注意:狀態碼200表示請求發送/接受成功,不表示業務處理成功
        _s.success(result, status, xhr);
      } else {
        _s.error(xhr, status, e);
      }
    });
    // 請求結束
    xhr.addEventListener('loadend', e => {
      _s.complete(xhr, xhr.status);
    });
    // 請求出錯
    xhr.addEventListener('error', e => {
      _s.error(xhr, xhr.status, e);
    });
    // 請求超時
    xhr.addEventListener('timeout', e => {
      _s.error(xhr, 408, e);
    });
    let useUrlParam = false;
    let sType = _s.type.toUpperCase();
    // 若是是"簡單"請求,則把data參數組裝在url上
    if (sType === 'GET' || sType === 'DELETE') {
      useUrlParam = true;
      _s.url += http.getUrlParam(_s.url, _s.data);
    }
    // 初始化請求
    xhr.open(_s.type, _s.url, _s.async);
    // 設置指望的返回數據類型
    xhr.responseType = _s.dataType;
    // 設置請求頭
    for (const key of Object.keys(_s.headers)) {
      xhr.setRequestHeader(key, _s.headers[key]);
    }
    // 設置超時時間
    if (_s.async && _s.timeout) {
      xhr.timeout = _s.timeout;
    }
    // 發送請求.若是是簡單請求,請求參數應爲null.不然,請求參數類型須要和請求頭Content-Type對應
    xhr.send(useUrlParam ? null : http.getQueryData(_s.data));
  },
  // 把參數data轉爲url查詢參數
  getUrlParam: (url, data) => {
    if (!data) {
      return '';
    }
    let paramsStr = data instanceof Object ? http.getQueryString(data) : data;
    return (url.indexOf('?') !== -1) ? paramsStr : '?' + paramsStr;
  },
  // 獲取ajax請求參數
  getQueryData: (data) => {
    if (!data) {
      return null;
    }
    if (typeof data === 'string') {
      return data;
    }
    if (data instanceof FormData) {
      return data;
    }
    return http.getQueryString(data);
  },
  // 把對象轉爲查詢字符串
  getQueryString: (data) => {
    let paramsArr = [];
    if (data instanceof Object) {
      Object.keys(data).forEach(key => {
        let val = data[key];
        // todo 參數Date類型須要根據後臺api酌情處理
        if (val instanceof Date) {
          // val = dateFormat(val, 'yyyy-MM-dd hh:mm:ss');
        }
        paramsArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
      });
    }
    return paramsArr.join('&');
  }
}

3、vue-resource請求

        vue-resource是Vue.js的一款插件,它能夠經過XMLHttpRequest或JSONP發起請求並處理響應。也就是說,$.ajax能作的事情,vue-resource插件同樣也能作到,並且vue-resource的API更爲簡潔。另外,vue-resource還提供了很是有用的inteceptor功能,使用inteceptor能夠在請求前和請求後附加一些行爲,好比使用inteceptor在ajax請求時顯示loading界面。面試

特色
  1. 體積小
    vue-resource很是小巧,在壓縮之後只有大約12KB,服務端啓用gzip壓縮後只有4.5KB大小,這遠比jQuery的體積要小得多。
  2. 支持主流的瀏覽器
    和Vue.js同樣,vue-resource除了不支持IE 9如下的瀏覽器,其餘主流的瀏覽器都支持。
  3. 支持Promise API和URI Templates
    Promise是ES6的特性,Promise的中文含義爲「先知」,Promise對象用於異步計算。
    URI Templates表示URI模板,有些相似於ASP.NET MVC的路由模板。
  4. 支持攔截器
    攔截器是全局的,攔截器能夠在請求發送前和發送請求後作一些處理。
    攔截器在一些場景下會很是有用,好比請求發送前在headers中設置access_token,或者在請求失敗時,提供共通的處理方式。
經常使用api
  1. get(url, [options])
  2. head(url, [options])
  3. delete(url, [options])
  4. jsonp(url, [options])
  5. post(url, [body], [options])
  6. put(url, [body], [options])
  7. patch(url, [body], [options])
客戶端請求方法 服務端處理方法
this.$http.get(...) Getxxx
this.$http.post(...) Postxxx
this.$http.put(...) Putxxx
this.$http.delete(...) Deletexxx
option詳解
參數 類型 描述
url string 請求的URL
method string 請求的HTTP方法,例如:'GET', 'POST'或其餘HTTP方法
body Object, FormData string request body
params Object 請求的URL參數對象
headers Object request header
timeout number 單位爲毫秒的請求超時時間 (0 表示無超時時間)
before function(request) 請求發送前的處理函數,相似於jQuery的beforeSend函數
progress function(event) ProgressEvent回調處理函數
credentials boolean 表示跨域請求時是否須要使用憑證
emulateHTTP boolean 發送PUT, PATCH, DELETE請求時以HTTP POST的方式發送,並設置請求頭的X-HTTP-Method-Override
emulateJSON boolean 將request body以application/x-www-form-urlencoded content type發送

4、fetch

  1. fetch是基於promise實現的,也能夠結合async/await
  2. fetch請求默認是不帶cookie的,須要設置fetch(URL,{credentials:’include’})。 
  3. Credentials有三種參數:same-origin,include,*
  4. 服務器返回400 500 狀態碼時並不會reject,只有網絡出錯致使請求不能完成時,fetch纔會被reject
  5. 全部版本的 IE 均不支持原生 Fetch
  6. fetch是widow的一個方法
fetch(url).then(function(response) {
 return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(e) {
  console.log("Oops, error");
});

        可配合es6的箭頭函數進行使用ajax

fetch(url).then(response => response.json())
 .then(data => console.log(data))
 .catch(e => console.log("Oops, error", e))

5、axios

        Axios 是一個基於 promise 的 HTTP 庫,能夠用在瀏覽器和 node.js 中

特色
  • 從瀏覽器中建立XMLHttpRequests
  • 從 node.js 建立http請求
  • 支持PromiseAPI
  • 攔截請求和響應
  • 轉換請求數據和響應數據
  • 取消請求
  • 自動轉換 JSON 數據
  • 客戶端支持防護XSRF
經常使用api
  1. axios.request(config)
  2. axios.get(url[, config])
  3. axios.delete(url[, config])
  4. axios.head(url[, config])
  5. axios.options(url[, config])
  6. axios.post(url[, data[, config]])
  7. axios.put(url[, data[, config]])
  8. axios.patch(url[, data[, config]]
實例

get請求

// 爲給定 ID 的 user 建立請求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可選地,上面的請求能夠這樣作
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

post請求

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

併發請求

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 兩個請求如今都執行完成
  }));

攔截器

// 添加請求攔截器
axios.interceptors.request.use(function (config) {
    // 在發送請求以前作些什麼
    return config;
  }, function (error) {
    // 對請求錯誤作些什麼
    return Promise.reject(error);
  });

// 添加響應攔截器
axios.interceptors.response.use(function (response) {
    // 對響應數據作點什麼
    return response;
  }, function (error) {
    // 對響應錯誤作點什麼
    return Promise.reject(error);
  });

取消請求

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 處理錯誤
  }
});

// 取消請求(message 參數是可選的)
source.cancel('Operation canceled by the user.');

        固然,不管選擇哪種方式都須要自身結合業務的須要和自個人認知,沒有哪一個絕對的優秀,也沒有哪一個絕對不優秀。根據自身的經驗以及相關資料的查找,總結了《前端常見面試》這個系列 ,後續若是有更多的內容,我也會逐步去更新或者補充這個系列,指望可以對你們都有所幫助,歡迎你們轉發和點贊關注。本系列的相關文章以下:

  1. 前端常見面試-css篇
  2. 前端常見面試-存儲/緩存篇
  3. 前端常見面試-js篇
  4. 前端常見面試-進階篇
  5. 前端常見面試-vue篇
相關文章
相關標籤/搜索