配置請求地址:config->index.js
一個專案里通常有一個config->index.js,該檔案包含了當前專案的請求地址,以及專案的版本資訊,
// 請求地址
const API_URL_DEV = 'http://xxx.xxx.xxx.net:81/xxx' // 測驗介面
const API_URL_TRIAL = 'http://xxx.xxx.xxx.net:81/xxx' // 體驗版介面
const API_URL_PROD = 'http://xxx.xxx.xxx.net:81/xxx' // 線上介面
上面就是api請求的baseUrl,在后續配置axios的時候會用到,在專案開發中,有時候會切換開發版和體驗版,就是更改此處的地址,
微信小程式里需要區分一件事,那就是當前的運行環境,是否是開發環境,
微信小程式官方提供了 wx.getAccountInfoSync()可以獲取小程式版本的appid以及小程式的版本資訊,根據envVersion來判斷當前小程式是線下環境還是線上環境,

let {
miniProgram: {
envVersion,
version
}
} = wx.getAccountInfoSync() // 獲取小程式版本資訊
將獲取版本資訊的操作封裝成一個函式,根據運行環境配置小程式版本資訊和apiUrl
function getparamsByEnv() {
/**
* 官方提供:wx.getAccountInfoSync()獲取小程式版本資訊,以及appid
* 模擬當前環境
* 線下的是 'develop' 線上是 'prod'
*/
let {
miniProgram: {
envVersion,
version
}
} = wx.getAccountInfoSync() // 獲取小程式版本資訊
// 回傳的引數
let params = {
apiUrl: '',
version: version,
tester: true
}
switch (envVersion) {
case 'develop':
params.apiUrl = API_URL_DEV // 此處對應上面配置的線下baseUrl介面
params.version = '1.0.2'
break
case 'trial':
params.apiUrl = API_URL_TRIAL // 此處對應上面配置的體驗版baseUrl介面
params.version = '1.0.2'
break
default:
params.apiUrl = API_URL_PROD // 此處對應上面配置的線上baseUrl介面
params.tester = false
break
}
return params // 配置完成后回傳params
}
完整的config.js配置
// 請求地址
const API_URL_DEV = 'http://xxx.xxx.xxx.net:81/xxx' // 測驗介面
const API_URL_TRIAL = 'http://xxx.xxx.xxx.net:81/xxx' // 體驗版介面
const API_URL_PROD = 'http://xxx.xxx.xxx.net:81/xxx' // 線上介面
const envParams = getparamsByEnv()
export default envParams.apiUrl // 匯出apiUrl
export const version = envParams.version // 匯出版本資訊
export const tester = envParams.tester // 匯出tester
/**
* 區分小程式當前運行環境
* @return {Boolean} 是否是開發環境
*/
function getparamsByEnv() {
/**
* 官方提供:wx.getAccountInfoSync()獲取小程式版本資訊,以及appid
* 模擬當前環境
* 線下的是 'develop' 線上是 'prod'
*/
let {
miniProgram: {
envVersion,
version
}
} = wx.getAccountInfoSync() // 獲取小程式版本資訊
let params = {
apiUrl: '',
version: version,
tester: true
}
switch (envVersion) {
case 'develop':
params.apiUrl = API_URL_DEV
params.version = '1.0.2'
break
case 'trial':
params.apiUrl = API_URL_TRIAL
params.version = '1.0.2'
break
default:
params.apiUrl = API_URL_PROD
params.tester = false
break
}
return params
}
配置request.js
在這個檔案其實就是配置axios,需要引入axios以及上面配置的config.js檔案
import axios from 'axios'
import mpAdapter from 'axios-miniprogram-adapter'
axios.defaults.adapter = mpAdapter
import API_URL from '../config/index' // apiUrl
axios有三個配置項,分別是:baseUrl、請求攔截器、回應攔截器,下面分別就這些配置項進行配置,
配置請求baseUrl
引入config.js的apiUrl,在axios的baseUrl中配置
const service = axios.create({
baseURL: API_URL, // url = base url + request url
})
配置請求攔截器:service.interceptors.request.use
在請求攔截器內通常會做一些配置,比如:在請求頭中攜帶token,在請求的時候彈出“加載中”告訴用戶正在發生什么等等,通常只要發送請求,都會經過請求攔截器,
let ajaxTimes = 0; // 狀態
// 請求攔截器
service.interceptors.request.use(function (config) {
// config就是請求的配置資訊,里面包含baseUrl地址,headers請求頭,url請求介面等資訊
// 在發送請求前,可以對config做一些配置操作(加鹽)
// 獲取token
if(wx.getStorageSync('token')){
// 如果token存在,那么在請求頭上帶上token
config.headers['access_token'] = wx.getStorageSync('token')
}
// 請求的時候,添加一個彈框,告訴用戶正在發生什么
// config.url != 'xxx/xxx' 請求某個介面不彈出提示
if (!ajaxTimes++ && config.url != '/lottery/activity/get-prize'){
wx.showLoading({ title: '加載中···' }) // 其實把wx.showLoading寫在請求攔截器里都會生效,這里只是做了一個ajaxTimes的判斷,優化了提示彈框
}
return config; // 回傳配置資訊-也就是請求頭之類的
},function (error){
// 處理錯誤請求
return Promise.reject(error)
})
配置回應攔截器:service.interceptors.response.use
只要請求介面,介面回應并回傳,都會走回應攔截器,可以在回應攔截器內做一些配置,比如請求日志、token過期處理、賬戶封禁處理、服務器錯誤處理、回應成功處理等等,
// 添加回應攔截器
service.interceptors.response.use(function (response) {
// response回傳上方請求攔截器的config配置資訊,data后臺介面回傳的資料,headers服務器回應頭等資訊
// 由于微信小程式的 toast 和 loading 相關介面可以相互混用,所以需要取消混用提示,也是關聯上方的“加載中”優化
if (ajaxTimes > 0 && --ajaxTimes === 0) {
wx.hideLoading({noConflict:true}) // // 取消混用提示
}
// 這里回傳的response.data就是后臺介面回傳的資料
const res = response.data
// 如果回傳的code不是200或201,則判斷為錯誤
if(res.code && res.code !== 200 && res.code !== 201){
// 分別對這些錯誤進行對應的處理
if(res.code === 1004){
// 1004狀態碼表示token過期,需要重新獲取token,并在獲取token后,重新請求介面,清除token
return reSetToken(response.config) // 這里呼叫獲取token的方法,后面會進行配置
} else if(res.code === 9001){
// 回傳9001狀態碼處理,通過wx.login獲取code
if (res.message.indexOf('code been used') !== -1) {
getApp().globalData.userInfo._getLoginCode()
} else if (res.message.indexOf('invalid code') !== -1) {
console.log('invalid code')
}
return Promise.reject(res)
} else if (res.code === 400 || res.code === 500){
// 回傳400或500狀態碼,表示服務器錯誤或者介面請求例外
wx.showToast({title: `${res.message}`,icon: 'none'})
return Promise.reject(res)
} else if(res.code == 30011){ // 賬戶封禁
// 回傳30011狀態碼,表示該賬號已封禁,如果想對封禁的賬戶做一些操作可以將回傳的資訊攜帶并跳轉到封禁頁,封禁頁展示封禁的原有和資訊,用戶可以在封禁頁做封禁申訴等操作
const info = res.message;
wx.reLaunch({
url: `/pages/account/index?info=${info}`,
})
}
return Promise.reject(res) // 其他的錯誤狀態碼就直接reject
} else {
return res
}
}, function (error) {
// 處理回應錯誤
if (ajaxTimes > 0 && --ajaxTimes === 0) {
wx.hideLoading({noConflict:true})
}
return Promise.reject(error);
}
token過期后重新獲取token,在回應攔截器里說過,回傳狀態1004表示token過期,在這里封裝重新獲取token的方法,在回應攔截器狀態1004處呼叫,
let tokenLoad = false
// 重新獲取token
function reSetToken(params) {
// 這里的params就是response.config的資訊
return new Promise(async (resolve,reject) => {
// 用函式形式將resolve存入,等待重繪后再執行
const app = getApp() // 獲取小程式全域唯一的 App 實體
if(!app){
return console.log("app undefined")
}
wx.queue.asyncWait("login_back", () => {
service(params).then(res => {
resolve(res)
}, err => {
reject(err)
})
},params.url)
// tokenLoad = true什么都不做,false走重新發起登錄的流程
if(tokenLoad) {
console.log("中斷重新獲取token")
} else {
// 將tokenLoad狀態更改為true
tokenLoad = true
try {
// 重新發起登錄,呼叫發起登錄的方法
app.globalData.userInfo.Login().then(res => {
if(res === 'notBindPhone') {
app.awaitLoginDialog('request')
}
tokenLoad = false // 登錄成功后將tokenLoad改為false,等待下次token過期重新發起登錄
}).catch(()=>{
tokenLoad = false
})
} catch (error) {
// 重新獲取token報錯,說明用戶沒注冊,需要喚醒注冊彈窗,如果在tabbar頁面,就不自動喚醒
app.awaitLoginDialog('request')
tokenLoad = false
reject(error)
}
}
})
}
完整的request.js配置
import axios from 'axios'
import mpAdapter from 'axios-miniprogram-adapter'
axios.defaults.adapter = mpAdapter
import API_URL from '../config/index'
const service = axios.create({
baseURL: API_URL, // url = base url + request url
})
let ajaxTimes = 0
// 請求攔截器
service.interceptors.request.use(function (config) {
// config是請求的配置資訊,內部有baseUrl地址,headers請求頭,url請求介面等資訊
// console.log('請求攔截器',config);
// 發送請求之前你可以在這里對config做一些配置
// 獲取token
if (wx.getStorageSync('token')) {
// 如果token存在,那么在請求頭上帶上token
config.headers['access_token'] = wx.getStorageSync('token')
}
// 請求的時候,添加一個彈框wx.showLoading告訴用戶正在加載中
// !ajaxTimes++是因為請求可能不止一次,請求的時候這種"加載中"的提醒優化,其實只需要顯示一次即可,所以需要做一個判斷,ajaxTimes == 0的時候提示一次,后續ajaxTimes++都不會提示,每次進新頁面或重繪都會重置ajaxTimes == 0 ,這里做的操作其實就是為了優化,減少提示的次數,
if (!ajaxTimes++ && config.url != '/lottery/activity/get-prize' && config.url != '/lottery/activity/time'){
wx.showLoading({ title: '加載中···' }) // 其實把wx.showLoading寫在請求攔截器里都會生效,這里只是做了一個ajaxTimes的判斷,優化了提示彈框
}
return config;
}, function (error) {
// 處理請求錯誤
return Promise.reject(error);
});
// 添加一個回應攔截器
service.interceptors.response.use(function (response) {
// response回傳請求攔截器的config配置資訊,data后臺介面回傳的資料,headers服務器回應頭等資訊
// console.log('回應攔截器',response);
if (ajaxTimes > 0 && --ajaxTimes === 0) {
wx.hideLoading({noConflict:true})
}
// 這里回傳的response.data就是后臺介面回傳的資料
const res = response.data
console.log('請求日志:',response); // 請求日志
// 如果自定義代碼不是200或201,則判斷為錯誤.
if (res.code && res.code !== 200 && res.code !== 201 && res.code !== 2001 && res.code !== 2002) {
if (res.code === 1004) {
// 1004狀態碼表示token過期,這是需要重新獲取token,并且在獲取完token之后,重新請求介面,清除token
return reSetToken(response.config)
} else if (res.code === 9001) {
if (res.message.indexOf('code been used') !== -1) {
getApp().globalData.userInfo._getLoginCode()
} else if (res.message.indexOf('invalid code') !== -1) {
console.log('invalid code')
}
return Promise.reject(res)
} else if (res.code === 400 || res.code === 500) {
wx.showToast({title: `${res.message}`,icon: 'none'})
return Promise.reject(res)
} else if (res.code === 30011) { // 賬戶封禁
const info = res.message;
// 根據code判斷該賬戶是否封禁,如果封禁,則攜帶資訊跳轉到封禁頁
wx.reLaunch({
url: `/pages/account/index?info=${info}`,
})
}
return Promise.reject(res)
} else {
return res
}
}, function (error) {
// 處理回應錯誤
if (ajaxTimes > 0 && --ajaxTimes === 0) {
wx.hideLoading({noConflict:true})
}
return Promise.reject(error);
});
let tokenLoad = false
// 重新獲取token
function reSetToken(params) {
// console.log('重新獲取token:',params);
return new Promise(async (resolve, reject) => {
// 用函式形式將 resolve 存入,等待重繪后再執行
const app = getApp()
if (!app) {
console.error("app undefind");
return
}
wx.queue.asyncWait("login_back", () => {
service(params).then(res => {
resolve(res)
}, err => {
reject(err)
})
},params.url)
// true什么都不做,false走重新發起登錄流程
if (tokenLoad) {
console.log("中斷重新獲取token");
} else {
// 將tokenLoad狀態更改為true
tokenLoad = true
try {
// 重新發起登錄
app.globalData.userInfo.Login().then(res => {
// console.log('發起登錄',res);
if (res === 'notBindPhone') {
app.awaitLoginDialog('request')
}
tokenLoad = false // 登錄成功后將tokenLoad改為false,等待下次token過期重新發起登錄
}).catch(() => {
tokenLoad = false
})
} catch (error) {
// 重新獲取token報錯,說明用戶沒有注冊,需要喚起注冊彈窗,如果是在tabbar頁面,就不自動喚起
// console.log(error, '請求token失敗報錯')
app.awaitLoginDialog('request')
tokenLoad = false
reject(error)
}
}
})
}
export default service
getApp()為微信小程式的全域唯一App實體,用戶的登錄方法可以掛載到App實體當中,在需要喚醒登錄處獲取getApp()中掛載的登錄方法即可喚醒登錄,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/544770.html
標籤:JavaScript
上一篇:【JavaScript】JS引擎中執行背景關系如何順序執行代碼
下一篇:css優先級和權重
