在react項目中,和後臺交互獲取數據這塊,咱們一般使用的是axios庫,它是基於promise的http庫,可運行在瀏覽器端和node.js中。他有不少優秀的特性,例如攔截請求和響應、取消請求、轉換json、客戶端防護XSRF等。若是還對axios不瞭解的,能夠移步axios文檔。javascript
//使用npm安裝
npm install axios;
//使用yarn安裝
yarn add axios
複製代碼
在項目根目錄中,新建一個request文件夾,而後在裏面新建一個index.js和一個api.js文件。index.js文件用來封裝咱們的axios,api.js用來統一管理咱們的接口。java
//在index.js中引入axios
import axios from 'axios';
//引入qs模塊,用來序列化post類型的數據
import QS from 'qs';
//antd的message提示組件,你們可根據本身的ui組件更改。
import { message } from 'antd'
複製代碼
咱們的項目環境可能有開發環境、測試環境和生產環境。咱們經過node的環境變量來匹配咱們的默認的接口url前綴。這裏須要node的全局變量process
,process.env.NODE_ENV
能夠區分是開發環境仍是生產環境。node
//保存環境變量
const isPrd = process.env.NODE_ENV == 'production';
//區分開發環境仍是生產環境基礎URL
export const basciUrl = isPrd ? 'https://www.production.com' : 'http://www.development.com'
複製代碼
這裏導出基礎URL是爲了防止有其餘地方用到資源不同,須要區分生產環境仍是開發環境,導入就直接能夠用了。react
咱們在發送請求前能夠進行一個請求的攔截,爲何要攔截呢,咱們攔截請求是用來作什麼的呢?好比,有些請求是須要用戶登陸以後才能訪問的,或者post
請求的時候,咱們須要序列化咱們提交的數據。這時候,咱們能夠在請求被髮送以前進行一個攔截,從而進行咱們想要的操做。ios
//設置axios基礎路徑
const service = axios.create({
baseURL: basicUrl
})
// 請求攔截器
service.interceptors.request.use(config => {
// 每次發送請求以前本地存儲中是否存在token,也能夠經過Redux這裏只演示經過本地拿到token
// 若是存在,則統一在http請求的header都加上token,這樣後臺根據token判斷你的登陸狀況
// 即便本地存在token,也有可能token是過時的,因此在響應攔截器中要對返回狀態進行判斷
const token = window.localStorage.getItem('userToken') || window.sessionStorage.getItem('userToken');
//在每次的請求中添加token
config.data = Object.assign({}, config.data, {
token: token,
})
//設置請求頭
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
}
config.data = QS.stringify(config.data)
return config
}, error => {
return error;
})
複製代碼
這裏說一下token,通常是在登陸完成以後,將用戶的token經過localStorage或者sessionStorage存在本地,而後用戶每次在進入頁面的時候(即在main.js
中),會首先從本地存儲中讀取token,若是token存在說明用戶已經登錄過,則更新Redux中的token狀態。而後,在每次請求接口的時候,都會在請求的header中攜帶token,後臺人員就能夠根據你攜帶的token來判斷你的登陸是否過時,若是沒有攜帶,則說明沒有登陸過。npm
// 響應攔截器
service.interceptors.response.use(response => {
//根據返回不一樣的狀態碼作不一樣的事情
// 這裏必定要和後臺開發人員協商好統一的錯誤狀態碼
if (response.code) {
switch (response.code) {
case 200:
return response.data;
case 401:
//未登陸處理方法
break;
case 403:
//token過時處理方法
break;
default:
message.error(response.data.msg)
}
} else {
return response;
}
})
//最後把封裝好的axios導出
export default service
複製代碼
響應攔截器很好理解,就是服務器返回給咱們的數據,咱們在拿到以前能夠對他進行一些處理。例如上面的思想:若是後臺返回的狀態碼是200,則正常返回數據,不然的根據錯誤的狀態碼類型進行一些咱們須要的錯誤,具體返回的狀態碼須要處理那些流程還須要跟後臺開發人員協商。
上面的message.error()
方法時我引入的antd的庫提示組件,須要根據你的UI庫,對應使用提示組件json
整齊的api就像電路板同樣,即便再複雜也能很清晰整個線路。上面說了,咱們會新建一個api.js,而後在這個文件中存放咱們全部的api接口。axios
首先咱們在api.js中引入咱們封裝的axiosapi
//導入咱們封裝好的axios
import service from './index'
複製代碼
如今,例如咱們有這樣一個接口,是一個post請求:promise
http://www.development.com/api/v1/articleEdit
複製代碼
咱們能夠在api.js中這樣封裝:
export const apiArticleEdit = info => service.post('/api/v1/articleEdit', info);
複製代碼
咱們定義了一個apiArticleEdit
方法,這個方法有一個參數info,info是咱們請求接口時攜帶的參數對象。然後調用了咱們封裝的axios方法,第一個參數是咱們的接口地址,第二個參數是apiArticleEdit
的info參數,即請求接口時攜帶的參數對象。最後經過export導出apiArticleEdit
。
而後在咱們的頁面中能夠這樣調用咱們的api接口:
import React, { Component } from 'react'
import { apiArticleEdit } from './request/api'
export default class App extends Component {
componentDidMount() {
// 調用api接口,而且提供了兩個參數
let params = { type: 2, author: '北孤清茶' }
apiArticleEdit(params).then(res => {
// 獲取數據成功後的其餘操做
//.....
console.log(res)
})
}
render() {
return (
<div> </div>
)
}
}
複製代碼
其餘的api接口,就在api.js中繼續往下面擴展就能夠了。友情提示,爲每一個接口寫好註釋哦!!!
api接口管理的一個好處就是,咱們把api統一集中起來,若是後期須要修改接口,咱們就直接在api.js中找到對應的修改就行了,而不用去每個頁面查找咱們的接口而後再修改會很麻煩。關鍵是,萬一修改的量比較大。還有就是若是直接在咱們的業務代碼修改接口,一不當心還容易動到咱們的業務代碼形成沒必要要的麻煩。
好了,最後把完成的axios封裝代碼奉上。
//在index.js中引入axios
import axios from 'axios';
//引入qs模塊,用來序列化post類型的數據
import QS from 'qs';
//antd的message提示組件,你們可根據本身的ui組件更改。
import { message } from 'antd'
//保存環境變量
const isPrd = process.env.NODE_ENV == 'production';
//區分開發環境仍是生產環境基礎URL
export const basciUrl = isPrd ? 'https://www.production.com' : 'http://www.development.com'
//設置axios基礎路徑
const service = axios.create({
baseURL: basicUrl
})
// 請求攔截器
service.interceptors.request.use(config => {
// 每次發送請求以前本地存儲中是否存在token,也能夠經過Redux這裏只演示經過本地拿到token
// 若是存在,則統一在http請求的header都加上token,這樣後臺根據token判斷你的登陸狀況
// 即便本地存在token,也有可能token是過時的,因此在響應攔截器中要對返回狀態進行判斷
const token = window.localStorage.getItem('userToken') || window.sessionStorage.getItem('userToken');
//在每次的請求中添加token
config.data = Object.assign({}, config.data, {
token: token,
})
//設置請求頭
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
}
//序列化請求參數,否則post請求參數後臺接收不正常
config.data = QS.stringify(config.data)
return config
}, error => {
return error;
})
// 響應攔截器
service.interceptors.response.use(response => {
//根據返回不一樣的狀態碼作不一樣的事情
// 這裏必定要和後臺開發人員協商好統一的錯誤狀態碼
if (response.code) {
switch (response.code) {
case 200:
return response.data;
case 401:
//未登陸處理方法
break;
case 403:
//token過時處理方法
break;
default:
message.error(response.data.msg)
}
} else {
return response;
}
})
//最後把封裝好的axios導出
export default service
複製代碼