Ajax搭配Promise的簡單封裝

先說一下平時工做的狀況:
平常的工做業務中,與後端數據交互只用了兩種形式,GETPOST,寫業務代碼的時候傳的參數都是對象格式{name:'jason',age:27},通常都是這樣寫:jquery

Http.get('api/userCenter/bookList.json', {
    date: '2010',
    lang: 'en'
}).then(function(res) {
    console.log(res);
})

Http.post('api/userCenter/login.json', {
    mobile: 13821863666,
    psd: 123123
}).then(function(res) {
    console.log(this);
})

GET傳輸時,須要把對應的參數拼接在URL的後面;POST傳輸時,send的數據格式也主要只用到瞭如下三種:angularjs

  • Content-Type: application/x-www-form-urlencoded,send(data)中的data數據格式爲"name=jason&age=27",此時須要序列化參數對象
  • Content-Type: application/json,send(data)中的data數據格式爲"{"mobile":13821863666,"psd":123123}",此時須要用JSON.stringify()把參數對象轉換成json字符串
  • 使用FormData對象,直接send(FormDataObj)便可,此時不須要設置Content-Type

我就針對以上這些應用場景對ajax作了簡單的封裝,代碼以下:ajax

// http.js

// note:xhr的兼容寫法
// function XHR() {
//   if (window.XMLHttpRequest) return new XMLHttpRequest();
//   if (window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP');
//   return 'Not support XMLHttpRequest!';
// }

// 判斷是否爲純對象,好比這種格式 {'name': 'jason'} 是純對象,函數、數組等則不是
function isPlainObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

// 查詢字符串中每一個參數的名稱和值都必須使用 encodeURIComponent() 進行編碼,而後才能放到 URL 的末尾;
// 全部名-值對兒都必須由和號 ( & ) 分隔
function addURLParam(url, name, value) {
  url += (url.indexOf('?') == -1 ? '?' : '&');
  url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
  return url;
}

/**
 * Converts an object to x-www-form-urlencoded serialization.
 * http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
 * @param  {Object} obj
 * @return {String}
 */
function serialize(obj) {
  var query = '', name, value, fullSubName, subName, subValue, innerObj, i;

  for (name in obj) {
    value = obj[name];

    if (value instanceof Array) {
      for (i = 0; i < value.length; ++i) {
        subValue = value[i];
        fullSubName = name + '[' + i + ']';
        innerObj = {};
        innerObj[fullSubName] = subValue;
        query += serialize(innerObj) + '&';
      }
    }
    else if (value instanceof Object) {
      for (subName in value) {
        subValue = value[subName];
        fullSubName = name + '[' + subName + ']';
        innerObj = {};
        innerObj[fullSubName] = subValue;
        query += serialize(innerObj) + '&';
      }
    }
    else if (value !== undefined && value !== null)
      query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
  }

  return query.length ? query.substr(0, query.length - 1) : query;
}

function ajax(type, url, data, contentType) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();

    if (type.toUpperCase() === 'GET' && data) {
      for (key in data) {
        if (data.hasOwnProperty(key)) {
          url = addURLParam(url, key, data[key]);
        }
      }
    }

    /** post傳輸,當傳FormData類型的數據時,不須要設置Content-Type
     *  當數據格式爲純對象時
     *  默認設置'Content-Type'爲'application/x-www-form-urlencoded',對數據進行序列化
     *  若是'Content-Type'設置爲'application/json',數據直接傳json字符串
     **/
    if (type.toUpperCase() === 'POST' && isPlainObject(data)) {
      if (!contentType || contentType === 'application/x-www-form-urlencoded') {
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        data = serialize(data);
      } else {
        xhr.setRequestHeader('Content-Type', 'application/json');
        data = JSON.stringify(data);
      }
    }

    xhr.open(type, url, true);

    xhr.onload = function() {
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
        var res = JSON.parse(xhr.response);
        resolve(res);
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.timeout = 10000;
    xhr.ontimeout = function() {
      reject('連接超時!')
    };
    xhr.onerror = function() {
      reject('網絡錯誤!');
    };
    xhr.onabort = function() {
      reject('請求取消!');
    };

    xhr.send(type.toUpperCase() === 'GET' ? null : data); // 若是不須要經過請求主體發送數據,則必須傳入null,由於這個參數對有些瀏覽器來講是必需的
  });
}

export default {
  get: function(url, data) {
    return ajax('GET', url, data);
  },
  post: function(url, data, contentType) {
    return ajax('POST', url, data, contentType);
  }
}

以後就能夠在其餘文件中使用getpost這兩個接口:json

import Http from 'http'

Http.get('api/userCenter/bookList.json', {
    date: '2010',
    lang: 'en'
}).then(function(res) {
    console.log(res);
})

Http.post('api/userCenter/login.json', {
    mobile: 13821863666,
    psd: 123123
}).then(function(res) {
    console.log(this);
})

get的使用形式是Http.get(url, data)post的使用形式是Http.post(url, data, contentType),第三個參數contentType可選,當設置了對應的值時,http.js會對傳入的參數作不一樣格式化的處理。後端

相關文章
相關標籤/搜索