先說一下對比吧
Jquery ajax, Axios, Fetch區別之我見
引言
前端技術真是一個發展飛快的領域,我三年前入職的時候只有原生XHR和Jquery ajax,我們還曾被JQuery 1.9版本版本以下不支持大文件請求這個問題卡了半天(最后自己寫了原生的XHR請求)。一晃眼,JQuery ajax早已不能專美於前,axios和fetch都已經開始分別搶占“請求”這個前端高地。本文將會嘗試着闡述他們之間的區別,並給出自己的一些理解。
1 JQuery ajax
$.ajax({
type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function () {} });
這個我就不用多言了把,是對原生XHR的封裝,除此以外還增添了對JSONP的支持。有一說一的說一句,JQuery ajax經過多年的更新維護,真的已經是非常的方便了,優點無需多言;如果是硬要舉出幾個缺點,那可能只有
- 本身是針對MVC的編程,不符合現在前端MVVM的浪潮
- 基於原生的XHR開發,XHR本身的架構不清晰,已經有了fetch的替代方案
- JQuery整個項目太大,單純使用ajax卻要引入整個JQuery非常的不合理(采取個性化打包的方案又不能享受CDN服務)
盡管JQuery對我們前端的開發工作曾有着(現在也仍然有着)深遠的影響,但是我們可以看到隨着VUE,REACT新一代框架的興起,以及ES規范的完善,更多API的更新,JQuery這種大而全的JS庫,未來的路會越走越窄。
總結:廉頗老矣,尚能飯,但是總有飯不動的一天。
2 Axios
axios({
method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
Vue2.0之后,尤雨溪推薦大家用axios替換JQuery ajax,想必讓Axios進入了很多人的目光中。Axios本質上也是對原生XHR的封裝,只不過它是Promise的實現版本,符合最新的ES規范,從它的官網上可以看到它有以下幾條特性:
- 從 node.js 創建 http 請求
- 支持 Promise API
- 客戶端支持防止CSRF
- 提供了一些並發請求的接口(重要,方便了很多的操作)
這個支持防止CSRF其實挺好玩的,是怎么做到的呢,就是讓你的每個請求都帶一個從cookie中拿到的key, 根據瀏覽器同源策略,假冒的網站是拿不到你cookie中得key的,這樣,后台就可以輕松辨別出這個請求是否是用戶在假冒網站上的誤導輸入,從而采取正確的策略。
Axios既提供了並發的封裝,也沒有下文會提到的fetch的各種問題,而且體積也較小,當之無愧現在最應該選用的請求的方式。
總結:誰敢橫刀立馬,唯我Axios將軍!
3 Fetch
fetch號稱是AJAX的替代品,它的好處在《傳統 Ajax 已死,Fetch 永生》中提到有以下幾點:
- 符合關注分離,沒有將輸入、輸出和用事件來跟蹤的狀態混雜在一個對象里
- 更好更方便的寫法,諸如:
try { let response = await fetch(url); let data = response.json(); console.log(data); } catch(e) { console.log("Oops, error", e); }
坦白說,上面的理由對我來說完全沒有什么說服力,因為不管是Jquery還是Axios都已經幫我們把xhr封裝的足夠好,使用起來也足夠方便,為什么我們還要花費大力氣去學習fetch?
我認為fetch的優勢主要優勢就是:
- 更加底層,提供的API豐富(request, response)
- 脫離了XHR,是ES規范里新的實現方式
大家都喜歡新的東西,坦白說,作為一個前端工程師,我在使用原生XHR的時候,盡管偶爾覺得寫的丑陋,但是在使用了JQuery和axios之后,已經對這一塊完全無所謂了。當然,如果新的fetch能做的同樣好,我為了不掉隊也會選擇使用fetch。這個道理其實很好理解:你有一架殲8,魔改了N次,性能達到了殲10的水准,但是要是有個人給你拿來一架新的殲10,你也會毫不猶豫的選擇新的殲10——不僅僅是新,也代表了還有新的魔改潛力。
但是我最近在使用fetch的時候,也遇到了不少的問題:
- fetch是一個低層次的API,你可以把它考慮成原生的XHR,所以使用起來並不是那么舒服,需要進行封裝
例如:
1)fetch只對網絡請求報錯,對400,500都當做成功的請求,需要封裝去處理
2)fetch默認不會帶cookie,需要添加配置項
3)fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現的超時控制並不能阻止請求過程繼續在后台運行,造成了流量的浪費
4)fetch沒有辦法原生監測請求的進度,而XHR可以
PS: fetch的具體問題大家可以參考:《fetch沒有你想象的那么美》《fetch使用的常見問題及解決方法》
看到這里,你心里一定有個疑問,這鬼東西就是個半拉子工程嘛,我還是回去用Jquery或者Axios算了——其實我就是這么打算的。但是,必須要提出的是,我發現fetch在前端的應用上有一項xhr怎么也比不上的能力:跨域的處理。
我們都知道因為同源策略的問題,瀏覽器的請求是可能隨便跨域的——一定要有跨域頭或者借助JSONP,但是,fetch中可以設置mode為"no-cors"(不跨域),如下所示:
fetch('/users.json', { method: 'post', mode: 'no-cors', data: {} }).then(function() { /* handle response */ });
這樣之后我們會得到一個type為“opaque”的返回。需要指出的是,這個請求是真正抵達過后台的,所以我們可以使用這種方法來進行信息上報,在我們之前的image.src方法中多出了一種選擇,另外,我們在network中可以看到這個請求后台設置跨域頭之后的實際返回,有助於我們提前調試接口(當然,通過chrome插件我們也可以做的到)。總之,fetch現在還不是很好用,我嘗試過幾個fetch封裝的包,都還不盡如人意。
總結:酋長的孩子,還需成長
總結
如果你是直接拉到文章底部的,只需要知道現在無腦使用axios即可,Jquery老邁笨拙,fetch年輕稚嫩,只有Axios正當其年!
++++++++++++++++++++++++++++++++++++++++++++++我是一個騷氣的分界線++++++++++++++++++++++++++++++++++++++++++++++++++++
異步請求
D2Admin 使用 axios 作為異步請求工具,並做了一些封裝。
axios | 地址 |
---|---|
Github | https://github.com/axios/axios |
npm | https://www.npmjs.com/package/axios |
中文文檔 | https://www.kancloud.cn/yunye/axios/234845 |
#介紹
Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。
- 支持瀏覽器和node.js
- 支持promise
- 能攔截請求和響應
- 能轉換請求和響應數據
- 能取消請求
- 自動轉換JSON數據
- 瀏覽器端支持防止CSRF(跨站請求偽造)
#瀏覽器支持
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
---|---|---|---|---|---|
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |
使用方式
axios 默認的使用方式在這里不做介紹,D2Admin 推薦在您的項目中使用下面的方式獲取數據:
#設置接口地址
默認的請求地址在 d2-admin/.env
VUE_APP_API=/api/
上述設置將在您訪問 /demo/a
時實際去訪問 /api/demo/a
#區分不同環境設置接口地址
如果您希望不同的環境使用不同的請求地址,可以在 d2-admin/.env.development
中添加設置(示例):
VUE_APP_API=/api-dev/
這樣您在開發環境和正式環境就有了不同的公共請求地址,在開發環境訪問 /demo/a
時實際去訪問 /api-dev/demo/a
#通用配置
您在開始使用 D2Admin 開發您的項目之前,應該首先修改 d2-admin/src/plugin/axios/index.js
下的設置。
默認的設置需要遵循下面的數據返回格式約定:
{ // 和后台約定的狀態碼 code: 0, // 后台返回請求狀態信息 msg: '返回信息', // data 內才是真正的返回數據 data: { list: [ ... ] } }
在響應攔截器中處理完數據后將會返回:
{ list: [ ... ] }
#業務錯誤
當發生錯誤時返回的數據示例:
{ // 和后台約定的狀態碼 code: 'unlogin', // 后台返回請求狀態信息 msg: '用戶沒有登錄' }
如果針對某個錯誤指定處理方法,應該在響應攔截器中加入對應的代碼:
service.interceptors.response.use( response => { // 成功返回數據,在這里判斷和后台約定的狀態標識 } )
#http 錯誤
如果需要針對某個 http 錯誤指定處理方法,應該在響應攔截器中第二個參數中添加對應的代碼。
service.interceptors.response.use( response => {}, error => { // 發生 http 錯誤,在這里判斷狀態碼 } )
#不返回 code
在默認的設置中,如果您的接口沒有返回 code 字段,將不會進行狀態(非 http 狀態,而是和后台約定好的狀態類型)判斷,直接返回 axios 請求返回的數據。
例如接口返回如下數據:
{ list: [ ... ] }
在響應攔截器中判斷該接口沒有返回 code 字段,將會直接將返回:
{ list: [ ... ] }
#設計 API
假設您有一個返回數據的 API 接口,想訪問它,您首先應該在 d2-admin/src/api
文件夾內創建合適的文件目錄,例如:d2-admin/src/api/demo/business/table/1/index.js
,這個文件中應該導出一個或者多個請求:
import request from '@/plugin/axios' export function BusinessTable1List (data) { return request({ url: '/demo/business/table/1', method: 'post', data }) }
#使用 API 獲取數據
在上面的步驟中創建了 API 文件,您應該在頁面中這樣使用:
<script> import { BusinessTable1List } from '@/api/demo/business/table/1' export default { methods: { handleSubmit (form) { BusinessTable1List({ name: '' }) .then(res => { // 返回數據 }) .catch(err => { // 異常情況 }) } } } </script>
而不是在頁面中直接調用 axios。
TIP
雖然沒有強制規定,請注意您的 API 文件夾結構規律性
#模擬數據
詳見 插件 | 模擬數據
#跨域問題
如果您的前端項目和后端接口發生跨域,可以在本地配置代理:
devServer: { proxy: { '/api': { target: 'http://47.100.186.132/your-path/api', ws: true, changeOrigin: true, pathRewrite: { '^/api': '' } } } }
上述配置的結果是在請求 /api/login
時轉發到 http://47.100.186.132/your-path/api/login
。更多文檔見 Vue CLI 3 | devServer.proxy