一、前言
在沒有接觸 React、Angular、Vue 這類 MVVM 的前端框架之前,無法拋棄 Jquery 的重要理由,除了優秀的前端 DOM 元素操作性以外,能夠非常便捷的發起 http 請求也占有非常重要的地位。
既然我們已經開始使用 Vue 進行前端開發,拋棄了對頁面 DOM 元素的操作,難道,為了方便的發起 http 請求,還需要在項目中加載 jquery 或者是手動創建 http 請求嗎?
答案當然是不用的,作為目前主流的前端框架,開發者、社區早已經為我們提供好了解決方案。隨着 Vue 作者尤雨溪宣布不再維護 vue-resource,轉而推薦大家使用 axios,目前在 Vue 社區中 axios 開始占據 http 庫的主導地位,所以這一章我們就介紹下如何使用 axios 發起 http 請求。
學習系列目錄地址:https://www.cnblogs.com/danvic712/p/9549100.html
倉儲地址(前端):https://github.com/Lanesra712/VueTrial/blob/master/chapter02-bronze/front/axios.html
倉儲地址(后端):https://github.com/Lanesra712/VueTrial/tree/master/chapter02-bronze/rear/Sample
二、干貨合集
axios 是一個基於 Promise 的 http 客戶端,可以用於瀏覽器和 node.js。官方文檔對於 axios 庫的使用方法已經寫的很清楚了,所以這里只介紹如何與 Vue 進行結合,從而使用 axios 發起 http 請求。
這一章會涉及到簡單的前后端的數據交互,作為一名 .NETer,本篇文章將采用 ASP.NET Core Web API 作為后端服務,你可以根據自己的喜好進行選擇。當然,如果你之前並沒有接觸過后端,不知道怎么選擇的話,推薦你嘗試 .NET Core,示例的后端項目我也會同步放在 Github 上。
PS:在后端模板項目上,我會添加對於 Swagger API 文檔的支持,以及在后端程序中進行配置跨域請求,從而允許后端接口可以接受跨域請求的訪問。這些內容並不會在本篇文章中展現,如果你需要詳細了解,你可以查看另一個系列的文章(ASP.NET Core 項目實戰)那里會介紹一些關於 ASP.NET Core 項目的開發,兩個系列相輔相成,后續所有涉及到前后端的交互開發,全部在此系列(ASP.NET Core 項目實戰)中進行呈現。
1、加載
同目前的前端發展方向相同,axios 可以從 npm、yarn、bower 這種前端包管理工具中進行下載,同時,也提供了 cdn 鏈接,方便我們在傳統的項目中進行使用。
// 使用 npm 加載 npm install axios // 使用 bower 加載 bower install axios // 使用 yarn 加載 yarn add axios
在這篇文章中,我還是與之前一樣,采用下載源文件的方式進行使用,在后續的前端框架搭建完成后再改用前端包管理工具進行加載。
// 使用 cdn 加載 <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2、get & post
相比於 put 請求和 delete 請求,get 請求和 post 請求是我們最常用的兩個方法,一個很常見的使用場景,我們通過 get 請求來搜索數據,通過 post 請求來提交數據。
在示例的后端接口中,提供了五個接口方法,分別對應了 get、post、put、delete 這四個 HTTP 謂詞。put 和 delete 對應的接口方法這里並沒有實現,這篇文章主要使用的是 get 和 post 謂詞對應的三個接口。
2.1、獲取所有的用戶數據(/api/user)
get 請求,加載全部的用戶數據,按照創建時間進行降序排列。
2.2、根據搜索條件搜索用戶數據(/api/user/query)
get 請求,根據用戶輸入框輸入的數據,從全部的用戶數據中查找出符合條件的數據,因為這里會存在多個查詢條件,其實並不太符合 Restful 的接口設計,所以這里我采用 ASP.NET Core 中的特性路由的方式,指定此路由為專門的數據查詢接口。
2.3、新增用戶數據(/api/user)
post 請求,提交一條新的用戶數據,因為是采用 Restful 風格的接口設計,所以請求的地址與獲取所有的用戶數據相同,僅僅是 http 謂詞的不同。
最終實現的前端頁面如下所示,頁面第一次加載時會加載全部的用戶數據;當用戶點擊搜索按鈕時,會根據頂部的三個輸入框中的值,從用戶數據中進行篩選;當點擊新增按鈕時,則會根據 Name 和 Email 輸入框中的值新增一條新的用戶數據。
首先我們需要在頁面加載的時候請求后端接口,去獲取我們的用戶數據,這里我們在 Vue 實例的 methods 中定義一個 getList 方法,在這個方法中我們去請求后端接口。
在之前學習 Vue 的生命周期鈎子函數時我們了解到,在 created 鈎子函數中,對於 Vue 實例的 data 和 methods 已經初始化完成,此時,整個 Vue 實例已經初始化完成。但是,初始化完成的 Vue 實例沒有與 DOM 進行綁定。所以,如果我們想要在頁面初始加載時就渲染出整個用戶信息表格,created 函數是能夠調用 getList 方法最早的一個鈎子函數。
在 axios 中,我們發起一個 http 請求后,在 then 回掉方法中進行請求成功后的數據處理,在 catch 回掉方法中捕獲請求失敗的信息。這里的 then 方法就相當於我們在 Jquery 中使用 ajax 時的 success 回調方法,而 catch 方法則是 error 回調。
axios.get('http://localhost:5000/api/user') .then(function (response) { console.log(response) }).catch(function (error) { console.log(error) })
從接口打印出的返回結果可以看到,接口返回的 response 中包含了五部分的信息。這里 data 屬性顯示的就是整個的用戶數據集合,在實際使用中,你需要與 http 響應狀態碼進行結合,考慮如果后端出現錯誤如何使前端知曉,從而相對友好的通知用戶。
{ // 后端接口返回的數據 data: {}, // 服務端接口返回的 HTTP 狀態碼 status: 200, // 服務端接口返回的 HTTP 狀態信息 statusText: 'OK', // 后端接口返回的響應 header 信息 headers: {}, // axios 發起的接口請求時的配置信息 config: {}, // 接口響應的請求信息 request: {} }
針對 axios 發起請求時的配置信息,我們可以自己進行配置。例如我們可以設置請求的接口域名是什么,設置 post 請求時的 Content-Type,或者針對前后端數據交互時經常使用的 Jwt Token 驗證,我們可以在請求的 header 中添加 token 信息,從而通過后端的權限驗證。
axios.defaults.baseURL = 'https://api.example.com'; axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
當我們獲取到所有的用戶數據后,我們就可以將結果值賦值給我們 Vue 實例中的 users 數據集合對象(這個 users 需要你事先在 Vue 實例的 data 中進行提前定義好)。
axios.get('http://localhost:5000/api/user') .then(function (response) { console.log(response) this.users = response.data }).catch(function (error) { console.log(error) })
如果你按照上面的寫法進行賦值,你會發現頁面上並沒有按照我們的想法渲染出數據。既然我們已經獲取到了后端接口返回的數據值,那么這里的問題就可能出現在賦值這上面。我們可以在 then 回調中打印 this.users 看看。
可以看到,這里的 this 指向的其實是瀏覽器的 window 對象,因此我們給 this.users 賦值最終是賦值到 window 對象上了。因為是 this 指向出了問題,所以這里我就直接采用箭頭函數的方式進行數據賦值,最終的實現代碼如下所示。
var vm = new Vue({ el: '#app', data: { id: '', name: '', email: '', users: [] }, created() { this.getList() }, methods: { getList() { axios.get('http://localhost:5000/api/user') .then(response => { this.users = response.data }).catch(error => { console.log(error) }) } }, });
搜索按鈕的功能與獲取所有用戶信息的代碼比較相似,這里我們需要將搜索的參數添加到 get 請求中。從下圖的瀏覽器控制台中可以看到,當點擊查詢按鈕之后,我們添加的參數會以 query 查詢字符串的方式添加到請求的 url 地址上。
var vm = new Vue({ el: '#app', data: { id: '', name: '', email: '', users: [] }, methods: { search() { axios.get('http://localhost:5000/api/user/query', { params: { id: this.id, name: this.name, email: this.email, } }).then(response => { this.users = response.data }).catch(error => { console.log(error) }) } }, });
與 get 請求相似,使用 axios 發起 post 請求也是在 then 回掉方法中獲取接口返回值,在 catch 回掉方法中捕獲錯誤信息。
var vm = new Vue({ el: '#app', data: { id: '', name: '', email: '', users: [] }, methods: { getList() { axios.get('http://localhost:5000/api/user') .then(response => { this.users = response.data }).catch(error => { console.log(error) }) }, add() { axios.post('http://localhost:5000/api/user', { name: this.name, email: this.email, }).then(response => { console.log(response) this.getList() }).catch(error => { console.log(error) }) } }, });
就像我們使用 jquery 發起 ajax 請求一樣,我們可以使用 $.ajax/$.post 方法去發起一個 get/post 請求,也可以在 $.ajax 方法中通過指定請求的 type 類型來確定我們是以 get 請求還是 post 請求的方式執行,在 axios 中也提供了相似的功能。
// get 請求 axios({ method: 'get', url: 'http://localhost:5000/api/user' }) // post 請求 axios({ method: 'post', url: 'http://localhost:5000/api/user', data: { name: this.name, email: this.email, } });
整個前端頁面完整的示例代碼以及實現的效果如下所示。
<div id="app"> <div class="card border-info mb-3" style="margin-top: 20px;"> <div class="card-header text-info"> <b>用戶信息</b> </div> <div class="card-body text-info form-inline"> <div class="form-row"> <div class="form-group"> <div class="input-group mb-2 mr-sm-2"> <div class="input-group-prepend"> <div class="input-group-text text-info"> Id </div> </div> <input type="text" class="form-control" id="id" v-model="id" autocomplete="off"> </div> </div> <div class="form-group"> <div class="input-group mb-2 mr-sm-2"> <div class="input-group-prepend"> <div class="input-group-text text-info"> Name </div> </div> <input type="text" class="form-control" id="name" v-model="name" autocomplete="off"> </div> </div> <div class="form-group"> <div class="input-group mb-2 mr-sm-2"> <div class="input-group-prepend"> <div class="input-group-text text-info"> Email </div> </div> <input type="email" class="form-control" id="email" v-model="email" autocomplete="off"> </div> </div> <div class="form-group"> <a class="btn btn-info" href="#" role="button" @click="search">搜索</a> <a class="btn btn-success" href="#" role="button" @click="add">新增</a> </div> </div> </div> </div> <table class="table table-striped table-bordered table-hover text-info"> <thead class="thead-inverse"> <tr> <th>Id</th> <th>Name</th> <th>Email</th> <th>Created On</th> </tr> </thead> <tbody> <tr v-for="item in users" :key="item.id"> <td scope="row">{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.email}}</td> <td>{{item.createdTime}}</td> </tr> </tbody> </table> </div> <script> var vm = new Vue({ el: '#app', data: { id: '', name: '', email: '', users: [] }, created() { this.getList() }, methods: { getList() { axios.get('http://localhost:5000/api/user') .then(response => { this.users = response.data }).catch(error => { console.log(error) }) }, search() { axios.get('http://localhost:5000/api/user/query', { params: { id: this.id, name: this.name, email: this.email, } }).then(response => { this.users = response.data }).catch(error => { console.log(error) }) }, add() { axios.post('http://localhost:5000/api/user', { name: this.name, email: this.email, }).then(response => { console.log(response) this.getList() }).catch(error => { console.log(error) }) } }, }); </script>
3、攔截器
在前后端分離的項目中,我們一般采用 Jwt token 的方式進行權限控制。前端在獲取數據之前,需要從后端獲取到 token 令牌。當前端獲取到后端回傳的 token 信息后,我們需要將此 token 信息保存下來,此后所有的請求都需要在請求的 header 信息中添加此 token 信息。那么,能不能有一種方式可以在觸發后端驗證之前,統一的進行 token 信息校驗,當判斷沒有包含 token 信息之后,前端直接跳轉到登錄頁面。
在 axios 中,我們可以將此類操作放置到攔截器中。你可以將 axios 中的攔截器看成是 ASP.NET Core 中的 Filters 過濾器,例如,這里的需求,我們完全可以將獲取到的 token 信息置於 request 請求攔截器中,在發起的每一次 http 請求時去校驗是否包含 token 信息,當沒有包含 token 信息時,就可以直接跳轉到登錄頁面。
這里因為我並沒有實現后端 token 驗證,所以這里就只是進行一個演示,你可以從瀏覽器的控制台中看到只要我們發起一個 http 請求,就會輸出的我們打印的信息。
// request 請求攔截 axios.interceptors.request.use(function (request) { // 對 request 進行攔截 if(true){ console.log('跳轉到登錄頁面') } return request; }, function (error) { // 在錯誤請求時進行操作 return Promise.reject(error); });
既然有針對發起 request 請求時的攔截器,毫無疑問,對於獲取到接口返回的 response 信息,我們同樣可以使用攔截器進行攔截。例如,在定義 restful 接口時,我們一般會根據 http 響應狀態碼去反映接口的調用是否成功。在每一個通過 axios 發起請求的 then 回掉方法中,我們都需要對獲取到響應狀態碼進行判斷,判斷接口的調用是否成功。
當我們使用攔截器后,我們完全可以在針對 response 的攔截器中進行統一的判斷。例如,當調用接口不成功時,http 響應狀態碼為 400,同時返回錯誤信息,我們完全可以在攔截器中進行判斷,當所有的接口響應狀態碼為 400 時,彈出后端返回的錯誤信息。
// response 請求攔截 axios.interceptors.response.use(function (response) { // 對 response 進行攔截 switch (response.status) { case 200: console.log('接口訪問成功') break case 400: console.log('提示錯誤信息') break case 401: console.log('重定向到登錄頁面') break } return response; }, function (error) { // 在錯誤請求時進行操作 return Promise.reject(error); });
三、總結
這篇文章主要是簡單介紹如何使用 axios 去實現發起一個 http 請求。至此,在現階段的 Vue 學習使用中,對於一些基礎知識點就已經完成了一個初步的梳理,接下來,從下一章開始,我會從 0 開始通過 Vue CLI 去搭建一個前端的項目模板,因為自己並不是一個前端開發人員,個人的關注點還在於 .NET Core 后端,所以這里可能並不會涉及到 webpack 相關的知識點。同時,一些在之前的學習中沒有涉及到的知識點也會在后續的文章中進行補充。之后,就像開篇時所說的那樣,Vue.js 牛刀小試 和 ASP.NET Core 項目實戰 相輔相成,后期的關注點將聚焦於如何通過 ASP.NET Core 和 Vue 進行前后端開發,歡迎持續關注~~~