[Vue 牛刀小試]:第十五章 - 傳統開發模式下的 axios 使用入門

 一、前言

  在沒有接觸 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 進行前後端開發,歡迎持續關注~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章