在TypeScript項目中搭配Axios封裝后端接口調(diào)用
前言
本來是想發(fā) next.js 開發(fā)筆記的,結(jié)果發(fā)現(xiàn)里面涉及了太多東西,還是拆分出來發(fā)吧~
本文記錄一下在 TypeScript 項目里封裝 axios 的過程,之前在開發(fā) StarBlog-Admin 的時候已經(jīng)做了一次封裝,不過那時是 JavaScript ,跟 TypeScript 還是有些區(qū)別的。
另外我在跟著 next.js 文檔開發(fā)的時候,注意到官方文檔推薦使用 @tanstack/react-query
來封裝請求類的操作,淺看了一下文檔之后感覺很不錯,接下來我會在項目里實踐。
定義配置
先創(chuàng)建一個 global 配置,src/utilities/global.ts
export default class Global { static baseUrl = process.env.NEXT_PUBLIC_BASE_URL }
這是在 next.js 項目,可以用 next 規(guī)定的環(huán)境變量,其他項目可以自行修改。
封裝 auth
認證這部分跟 axios 有點關(guān)系,但關(guān)系也不是很大,不過因為 axios 封裝里面需要用到,所以我也一并貼出來吧。
創(chuàng)建 src/utilities/auth.ts
文件
/** * 登錄信息 */ export interface LoginProps { token: string username: string expiration: string } /** * 認證授權(quán)工具類 */ export default abstract class Auth { static get storage(): Storage | null { if (typeof window !== 'undefined') { return window.localStorage } return null } /** * 檢查是否已登錄 * @return boolean */ public static isLogin() { let token = this.storage?.getItem('token') let userName = this.storage?.getItem('user') if (!token || token.length === 0) return false if (!userName || userName.length === 0) return false return !this.isExpired(); } /** * 檢查登錄是否過期 * @return boolean */ public static isExpired = () => { let expiration = this.storage?.getItem('expiration') if (expiration) { let now = new Date() let expirationTime = new Date(expiration) if (now > expirationTime) return true } return false } /** * 讀取保存的token * @return string */ public static getToken = () => { return this.storage?.getItem('token') } /** * 保存登錄信息 * @param props */ public static login = (props: LoginProps) => { this.storage?.setItem('token', props.token) this.storage?.setItem('user', props.username) this.storage?.setItem('expiration', props.expiration) } /** * 注銷 */ public static logout = () => { this.storage?.removeItem('token') this.storage?.removeItem('user') this.storage?.removeItem('expiration') } }
跟認證有關(guān)的邏輯我都放在 Auth
類中了
為了在 next.js 中可以愉快使用,還得做一些特別的處理,比如我增加了 storage
屬性,讀取的時候先判斷 window
是否存在。
封裝 axios
關(guān)于 API 的代碼我都放在 src/services
目錄下。
創(chuàng)建 src/services/api.ts
文件,代碼比較長,分塊介紹,可以看到所有配置相比之前 JavaScript 版本的都多了配置,對 IDE 自動補全非常友好。
先 import
import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults} from "axios"; import Global from '@/utilities/global' import Auth from "@/utilities/auth";
Axios 配置
定義一下 axios 的配置
const config: CreateAxiosDefaults<any> = { method: 'get', // 基礎(chǔ)url前綴 baseURL: `${Global.baseUrl}/`, // 請求頭信息 headers: { 'Content-Type': 'application/json;charset=UTF-8' }, // 參數(shù) data: {}, // 設(shè)置超時時間 timeout: 10000, // 攜帶憑證 withCredentials: true, // 返回數(shù)據(jù)類型 responseType: 'json' }
統(tǒng)一接口返回值
設(shè)置統(tǒng)一的接口返回值,這個和我在 StarBlog 后端里封裝的那套是一樣的,現(xiàn)在基本是我寫后端的標準返回值了,同時也發(fā)布了 CodeLab.Share
nuget包,可以快捷的引入這個統(tǒng)一的返回值組件。
// 統(tǒng)一接口返回值 export interface ApiResponse { data: any errorData: any message: string statusCode: number successful: boolean }
定義 ApiClient
最后就是定義了 ApiClient
類,有點模仿 C# 的 HttpClient
內(nèi)味了
這里面用到了 axios 的攔截器,發(fā)起請求的時候給 header 加上認證信息,返回的時候看看有沒有錯誤,如果是 401 unauthorized 的話就跳轉(zhuǎn)到登錄頁面。
export class ApiClient { private readonly api: AxiosInstance constructor() { this.api = axios.create({ ...config, }) this.api.interceptors.request.use( config => { config.headers.Authorization = `Bearer ${Auth.getToken()}` return config }, error => { return error }) this.api.interceptors.response.use( response => { return response }, error => { let reason = error if (error && error.response) { if (error.response.data) { reason = error.response.data if (!reason.message) reason.message = error.message } if (error.response.status === 401) { location.href = '/login' } } return Promise.reject(reason) } ) } public request(options: AxiosRequestConfig): Promise<ApiResponse> { return new Promise((resolve, reject) => { this.api(options).then((res: AxiosResponse<ApiResponse>) => { resolve(res.data) return false }).catch(error => { reject(error) }) }) } } export const api = new ApiClient() export default api
代碼比之前我在 StarBlog-Admin 里的簡單一些,我要盡可能用較少的代碼實現(xiàn)需要的功能。
編寫具體接口調(diào)用
所有的接口調(diào)用我都寫成 service (后端思維是這樣的)
這里以發(fā)短信接口為例
創(chuàng)建 src/services/common.ts
文件,從剛才定義的 api.ts
里面引入 ApiClient
的對象,直接調(diào)用 request
方法就完事了。
參數(shù)類型是 AxiosRequestConfig
,不對 axios 本身做什么修改,我感覺比之前用 Antd Pro 魔改的接口舒服一些。
import {api} from './api' export class SmsChannel { static local = 0 static aliyun = 1 static tencent = 2 } export default abstract class CommonService { public static getSmsCode(phone: string, channel: number = SmsChannel.local) { return api.request({ url: `api/common/getSmsCode`, params: {phone, channel} }) } }
小結(jié)
這樣封裝完比之前 StarBlog-Admin 的舒服很多,可惜之前那個項目用的是 vue2.x 似乎沒法用 TypeScript。
就這樣吧,大部分內(nèi)容還是在 next.js 開發(fā)筆記中。
參考資料
到此這篇關(guān)于在TypeScript項目中搭配Axios封裝后端接口調(diào)用的文章就介紹到這了,更多相關(guān)Axios封裝后端接口調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析為什么axios會有params和data兩個參數(shù)
本文給大家分享為什么axios會有params和data兩個參數(shù),先來回顧一下axios的基本使用,怎么發(fā)送一個請求,本文結(jié)合實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2023-10-10JavaScript學習小結(jié)(一)——JavaScript入門基礎(chǔ)
本教程比較適合javascript初學者,對javascript基本知識的小結(jié)包括變量,基本類型等知識點,需要的朋友一起來學習吧2015-09-09ajax如何實現(xiàn)頁面局部跳轉(zhuǎn)與結(jié)果返回
AJAX即“Asynchronous Javascript And XML”(異步JavaScript和XML),是指一種創(chuàng)建交互式網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù),通過在后臺與服務(wù)器進行少量數(shù)據(jù)交換,AJAX 可以使網(wǎng)頁實現(xiàn)異步更新,本篇文章給大家介紹ajax如何實現(xiàn)頁面局部跳轉(zhuǎn)與結(jié)果返回,感興趣的朋友一起來學習2015-08-08IE6-IE9不支持table.innerHTML的解決方法分享
讓ie6-ie9支持table.innerHTML,其實這里只是對table做了處理,對其他不支持的元素可以用類似的方案2012-09-09