xe-ajax 封裝 fetch 的異步請求函數

最新版本見 Github,點擊查看歷史版本javascript

  • 基本函數java

    • ajax ( options )
    • fetch ( url[, options] )
    • doAll ( iterable ) 併發多個
    • setup ( options ) 全局參數設置
    • interceptor 攔截器
    • AbortController 如何取消請求
    • Progress 上傳/下載進度監聽
  • 便捷函數git

    • doHead ( url[, options] )
    • doDelete ( url[, options] )
    • doJsonp ( url[, params, options] )
    • doGet ( url[, params, options] )
    • doPost ( url[, body, options] )
    • doPut ( url[, body, options] )
    • doPatch ( url[, body, options] )
    • headJSON ( url[, options] )
    • deleteJSON ( url[, options] )
    • jsonp ( url[, params, options] )
    • getJSON ( url[, params, options] )
    • postJSON ( url[, body, options] )
    • putJSON ( url[, body, options] )
    • patchJSON ( url[, body, options] )

入參

  • url(字符串) 請求地址,可被自定義 options 屬性覆蓋
  • params/body(可選,對象/數組) 要發送的數據,可被自定義 options 屬性覆蓋
  • options (可選,對象) 參數

options 參數

*: 只支持最新版本的瀏覽器。github

參數 類型 描述 默認值
url String 請求地址
baseURL String 基礎路徑
method String 請求方法 'GET'
params Object 表單查詢參數
body Object 提交主體內容
bodyType String 提交主體內容方式,能夠設置json-data,form-data 'json-data'
mode String 請求的模式, 能夠設置cors,no-cors,same-origin 'cors'
cache String 處理緩存方式,能夠設置default,no-store,no-cache,reload,force-cache,only-if-cached 'default'
credentials String 設置 cookie 是否隨請求一塊兒發送,能夠設置: omit,same-origin,include 'same-origin'
*redirect String 重定向模式, 能夠設置follow,error,manual 'follow'
*referrer String 能夠設置no-referrer,client或URL 'client'
*referrerPolicy String 能夠設置: no-referrer,no-referrer-when-downgrade,origin,origin-when-cross-origin,unsafe-url
*keepalive String 選項可用於容許請求超過頁面的生存時間
*integrity String 包括請求的subresource integrity值
jsonp String jsonp入參屬性名 'callback'
jsonpCallback String jsonp響應結果的回調函數名 默認自動生成函數名
timeout Number 設置請求超時
headers Object 請求頭包含信息
origin String 改變目標源 location.origin
transformParams Function (params,request) 用於改變URL參數
paramsSerializer Function (params,request) 自定義URL序列化函數
transformBody Function (body,request) 用於改變提交數據
stringifyBody Function (body,request) 自定義轉換提交數據的函數
validateStatus Function (response) 自定義校驗請求是否成功 默認200-299

Headers

屬性 類型 描述
set Function (name,value) 添加
append Function (name,value) 追加
get Function (name) 根據 name 獲取
has Function (name) 檢查 name 是否存在
delete Function (name) 根據 name 刪除
keys Function 以迭代器的形式返回全部 name
values Function 以迭代器的形式返回全部 value
entries Function 以迭代器的形式返回全部 [name, value]
forEach Function (callback,context) 迭代器

Response

屬性 類型 描述
body ReadableStream 返回一個只讀的數據流
bodyUsed Boolean 返回一個只讀的布爾值,表示內容是否已被讀取
headers Headers 返回一個只讀的響應頭對象
status Number 返回一個只讀的響應狀態碼
statusText String 返回一個只讀的與狀態碼相對應的狀態消息
url String 返回一個只讀的請求路徑
ok Boolean 返回一個只讀的布爾值,表示響應是否成功
redirected Boolean 返回一個只讀的布爾值,表示響應是否爲重定向請求的結果
type String 返回一個只讀的響應的類型
clone Function 複製一個新的 Response 對象
json Function 返回一個內容爲 JSON 的 Promise 對象
text Function 返回一個內容爲 Text 的 Promise 對象
blob Function 返回一個內容爲 Blob 的 Promise 對象
arrayBuffer Function 返回一個內容爲 ArrayBuffer 的 Promise 對象
formData Function 返回一個內容爲 FormData 的 Promise 對象

全局參數設置

import XEAjax from 'xe-ajax'

XEAjax.setup({
  // 除非 url 是絕對路徑('/api/list' 或 '//test.com/api/list' 或 'https://test.com/api/list'),
  // 不然 baseURL 會拼接在 url 以前
  baseURL: 'https://test.com',
  bodyType: 'json-data',
  credentials: 'include',
  headers: {
    'Accept': 'application/json, text/plain, \*/\*;'
  },
  validateStatus (response) {
    // 注:如何須要實現複雜的場景判斷,請使用攔截器
    //
    // 若是是 fetch 函數,則會將狀態賦值給 ok 屬性
    // 除了 fetch 函數,其餘函數若是狀態返回 false 則會進入 catch
    return response.status >= 200 && response.status < 300
  },
  transformParams (params, request) {
    // 用於在請求發送以前改變URL參數
    if (request.method === 'GET') {
      params.queryDate = params.queryDate.getTime()
    }
    return params
  },
  paramsSerializer (params, request) {
    // 自定義URL序列化函數,最終拼接在url
    // 執行順序 transformParams > paramsSerializer
    return XEAjax.serialize(params)
  },
  transformBody (body, request) {
    // 用於在請求發送以前改變提交數據
    body.startTime = body.startDate.getTime()
    return body
  },
  stringifyBody (body, request) {
    // 自定義格式化提交數據函數
    // 執行順序 transformBody > stringifyBody
    return JSON.stringify(body)
  }
})

示例

基本使用

const XEAjax = require('xe-ajax')

XEAjax.ajax({
  url: '/api/test/message/list',
  method: 'GET',
  params: {
    id: 1
  }
})
  .then(response => {
    if (response.ok) {
      // 請求成功
    } else {
      // 請求失敗
    }
  })
  .catch(e => {
    // 發生錯誤
    console.log(e.message)
  })

fetch 調用,返回一個結果爲 Response 的 Promise 對象

import XEAjax from 'xe-ajax'

XEAjax.fetch('/api/test/message/save', {
  method: 'POST',
  body: {
    name: 'test'
  }
})
  .then(response => {
    if (response.ok) {
      // 請求成功
    } else {
      // 請求失敗
    }
  }).catch(e => {
    // 發生錯誤
    console.log(e.message)
  })

// Response Text
XEAjax.fetch('/api/test/message/list')
  .then(response => {
    response.text().then(text => {
      // text
    })
  })

// Response JSON
XEAjax.fetch('/api/test/message/list')
  .then(response => {
    response.json().then(data => {
      // data
    })
  })

// Response Blob
XEAjax.fetch('/api/test/message/list')
  .then(response => {
    response.blob().then(blob => {
      // blob
    })
  })

// Response ArrayBuffer
XEAjax.fetch('/api/test/message/list')
  .then(response => {
    response.arrayBuffer().then(arrayBuffer => {
      // arrayBuffer
    })
  })

// Response FormData
XEAjax.fetch('/api/test/message/list')
  .then(response => {
    response.formData().then(formData => {
      // formData
    })
  })

// 使用 "application/json" 方式提交
let body1 = {
  name: 'u111',
  content: '123456'
}
XEAjax.fetchPost('/api/test/message/save', body1, {bodyType: 'json-data'})

// 使用 "application/x-www-form-urlencoded" 方式提交
let body2 = {
  name: 'u222',
  content: '123456'
}
XEAjax.fetchPost('/api/test/message/save', body2, {bodyType: 'form-data'})

// 使用 "application/x-www-form-urlencoded" 方式提交
let searchParams = new URLSearchParams();
searchParams.append('name', 'u222');
searchParams.append('content', '123456');
XEAjax.fetchPost('/api/test/message/save', searchParams);

// 使用 "multipart/form-data" 方式提交
let file = document.querySelector('#myFile').files[0]
let formData = new FormData()
formData.append('file', file)
XEAjax.fetchPost('/api/test/message/save', formData)

// 查詢參數和數據同時提交
XEAjax.fetchPost('/api/test/message/save', {name: 'u333', content: '123456'}, {params: {id: 111}})

XEAjax.fetchGet('/api/test/message/list')
XEAjax.fetchPut('/api/test/message/update', {name: 'u222'})
XEAjax.fetchDelete('/api/test/message/delete/1')

根據請求狀態碼(成功或失敗),返回一個包含響應信息的 Peomise 對象 (v3.4.0+)

import XEAjax from 'xe-ajax'

// 對請求的響應包含如下信息
// result => {data, status, statusText, headers}

// 根據 validateStatus 狀態校驗判斷完成仍是失敗
XEAjax.doGet('/api/test/message/list').then(result => {
  // 請求成功 result.data
}).catch(result => {
  // 請求失敗
})

XEAjax.doGet('/api/test/message/list/page/15/1')
XEAjax.doPost('/api/test/message/save', {name: 'u111'})
XEAjax.doPut('/api/test/message/update', {name: 'u222'})
XEAjax.doDelete('/api/test/message/delete/1')

根據請求狀態碼(成功或失敗),返回響應結果爲 JSON 的 Peomise 對象

import XEAjax from 'xe-ajax'

// 根據 validateStatus 狀態校驗判斷完成仍是失敗,直接能夠獲取響應結果
XEAjax.getJSON('/api/test/message/list').then(data => {
  // 請求成功 data
}).catch(data => {
  // 請求失敗
})

XEAjax.getJSON('/api/test/message/list/page/15/1')
XEAjax.postJSON('/api/test/message/save', {name: 'u111'})
XEAjax.putJSON('/api/test/message/update', {name: 'u222'})
XEAjax.deleteJSON('/api/test/message/delete/1')

jsonp 調用

import XEAjax from 'xe-ajax'

// 例子1
// 請求路徑: https://xuliangzhan.com/jsonp/test/message/list?callback=jsonp_xeajax_1521272815608_1
// 服務端返回結果: jsonp_xeajax_1521272815608_1([...])
XEAjax.fetchJsonp('/jsonp/test/message/list')
  .then(response => {
    if (response.ok) {
      response.json().then(data => {
        // data
      })
    }
  })

// 例子2
// 請求路徑: https://xuliangzhan.com/jsonp/test/message/list?cb=jsonp_xeajax_1521272815608_2
// 服務端返回結果: jsonp_xeajax_1521272815608_2([...])
XEAjax.doJsonp('/jsonp/test/message/list', null, {jsonp: 'cb'})
  .then(response => {
    // response.data
  })

// 例子3
// 請求路徑: https://xuliangzhan.com/jsonp/test/message/list/page/10/1?id=222&cb=func
// 服務端返回結果: func({page: {...}, result: [...])
XEAjax.jsonp('/jsonp/test/message/list/page/10/1', {id: 222}, {jsonp: 'cb',jsonpCallback: 'func'})
  .then(data => {
    // data
  })

併發多個請求

import XEAjax from 'xe-ajax'

// 併發多個
Promise.all([
  XEAjax.fetchGet('/api/test/message/list'),
  XEAjax.doGet('/api/test/message/list'),
  XEAjax.postJSON('/api/test/message/save'), {name: 'n1'})
]).then(datas => {
  // 全部異步完成以後執行
}).catch(e => {
  // 發生異常
})

// 競速,哪一個先請求完成執行哪一個
Promise.race([
  XEAjax.getJSON('/api/test/message/list'),
  XEAjax.getJSON('/api/test/message/list')
]).then(datas => {
  // 任意一個請求完成後執行
}).catch(e => {
  // 發生異常
})

// doAll 使用對象參數, 用法和 Promise.all 一致
let iterable2 = []
iterable2.push({url: '/api/test/message/list'})
iterable2.push({url: '/api/test/message/save', body: {name: 'n1'}}, method: 'POST'})
XEAjax.doAll(iterable2).then(datas => {
  // 全部異步完成以後執行
}).catch(e => {
  // 發生異常
})

嵌套請求

import XEAjax from 'xe-ajax'

// 相互依賴的嵌套請求
XEAjax.fetchGet('/api/test/message/info', {id: 3})
  .then(response => response.json())
  .then(data => XEAjax.fetchGet(`/api/test/message/delete/${data.id}`))
  .then(response => {
    if (response.ok) {
      response.json().then(data => {
        // data
      })
    }
  })
XEAjax.doGet('/api/test/message/info', {id: 3})
  .then(result => XEAjax.doGet(`/api/test/message/delete/${result.data.id}`))
  .then(result => {
    // result.data
  })
XEAjax.getJSON('/api/test/message/info', {id: 3})
  .then(data => XEAjax.getJSON(`/api/test/message/delete/${data.id}`))
  .then(data => {
    // data
  })

使用 async/await 處理異步

import XEAjax from 'xe-ajax'

async function init() {
  let list = await XEAjax.getJSON('/api/test/message/list')
  let data = await XEAjax.getJSON('/api/test/message/info', {id: list[0].id})
  console.log(list)
  console.log(data)
}

init()

上傳/下載

參數

屬性 類型 描述
onUploadProgress Function (event) 上傳進度監聽
onDownloadProgress Function (event) 下載進度監聽
meanSpeed Number 默認0關閉,設置速率爲均衡模式,每隔多少毫秒內計算平均速率
fixed Number 默認2位數

Progress 對象

屬性 類型 描述
autoCompute Boolean 是否自動計算進度,默認true
value Number 當前進度 %
loaded Object 已傳輸大小 {value: 原始大小B, size: 轉換後大小, unit: 轉換後單位}
total Object 總大小 {value: 原始大小B, size: 轉換後大小, unit: 轉換後單位}
speed Object 傳輸速度/秒 {value: 原始大小B, size: 轉換後大小, unit: 轉換後單位}
remaining Number 剩餘時間/秒
time Number 時間戳
import XEAjax from 'xe-ajax'

// 上傳、下載
let file = document.querySelector('#myFile').files[0]
let formBody = new FormData()
formBody.append('file', file)
XEAjax.fetchPost('/api/upload', formBody)
XEAjax.doPost('/api/upload', formBody)
XEAjax.postJSON('/api/upload', formBody)


// 上傳進度
// 建立一個進度監聽對象
let progress = new XEAjax.Progress()
// 監聽上傳進度
progress.onUploadProgress = evnt => {
  console.log(`進度:${progress.value}% ${progress.loaded.size}${progress.loaded.unit}${progress.total.size}/${progress.total.unit}; 速度:${progress.speed.size}/${progress.speed.unit}秒; 剩餘:${progress.remaining}秒`)
}
let file = document.querySelector('#myFile').files[0]
let formBody = new FormData()
formBody.append('file', file)
XEAjax.fetchPost('/api/upload', formBody, {progress})
// 進度:1% 176KB/14.26MB; 速度:1.69MB/秒; 剩餘:8秒
// 進度:3% 368KB/14.26MB; 速度:640KB/秒; 剩餘:22秒
// 進度:8% 1.16MB/14.26MB; 速度:1.56MB/秒; 剩餘:8秒
// ...
// 進度:99% 14.08MB/14.26MB; 速度:119.6KB/秒; 剩餘:2秒
// 進度:100% 14.26MB/14.26MB; 速度:114.4KB/秒; 剩餘:0秒


// 下載進度
// 建立一個進度監聽對象
let progress = new XEAjax.Progress()
// 監聽下載進度
progress.onDownloadProgress = evnt => {
  console.log(`進度:${progress.value}% ${progress.loaded.size}${progress.loaded.unit}${progress.total.size}/${progress.total.unit}; 速度:${progress.speed.size}/${progress.speed.unit}秒; 剩餘:${progress.remaining}秒`)
}
XEAjax.fetchGet('/api/download/file/1', {progress, method: 'GET'})

取消請求

AbortController 控制器對象

容許控制一個或多個取消指令請求ajax

import XEAjax from 'xe-ajax'

// 建立一個控制器對象
// 若是當前環境支持 AbortController,則使用原生的 AbortController
let controller = new XEAjax.AbortController()
// let controller = new AbortController() // 或者使用原生
// 獲取signal
let signal = controller.signal
// 給請求加入控制器 signal
XEAjax.fetchGet('/api/test/message/list', {id: 1}, {signal})
  .then(response => {
    // 請求成功
  }).catch(e => {
    // 請求被取消
  })
setTimeout(() => {
  // 終止請求
  controller.abort()
}, 50)

攔截器

攔截器能夠對請求以前和請求以後的任何參數以及數據作處理,注意要調用next執行下一步,不然將中止執行。json

Request 攔截器

XEAjax.interceptors.request.use(Function(request, next))api

import XEAjax from 'xe-ajax'

// 請求以前攔截器
XEAjax.interceptors.request.use((request, next) => {
  // 用於請求的權限攔截、設置請求頭、Token 驗證、參數等處理...

  // 設置參數
  request.params.version = 1
  // 設置 Token 驗證,預防 XSRF/CSRF 攻擊
  request.headers.set('X-Token', cookie('x-id'))

  // 調用 next(),繼續執行下一個攔截器
  next()
})

Response 攔截器

XEAjax.interceptors.response.use(Function(response, next[, request]), Function(response, next))數組

next( [, newResponse] )瀏覽器

屬性 類型 描述
status Number 設置響應的狀態碼
statusText String 設置與狀態碼對應的狀態消息
body Object 設置響應主體內容
headers Headers、Object 設置響應的頭信息
import XEAjax from 'xe-ajax'

// 請求完成以後攔截
XEAjax.interceptors.response.use((response, next) => {
  // 請求完成以後統一處理,例如校驗登陸是否失效、消息提示,特殊場景處理等...

  // 例子: 判斷登陸失效跳轉
  if (response.status === 403) {
    router.replace({path: '/login'})
  } else {
    next()
  }
})

// 請求完成以後改變響應結果
XEAjax.interceptors.response.use((response, next) => {
  // 例如,對全部請求結果進行處理,返回統一的數據
  response.json().then(data => {
    let { status, statusText, headers } = response
    let body = {
      message: status === 200 ? 'success' : 'error',
      result: data
    }
    // 改變響應結果並繼續執行下一個攔截器
    next({status, statusText, headers, body})
  })
}, (e, next) => {
  // 對全部請求錯誤返回統一的數據
  let body = {
    message: 'error',
    result: null
  }
  // 改變響應結果並繼續執行下一個攔截器
  next({status: 200, body})
})
相關文章
相關標籤/搜索