Browse Source

feat: 增加axios

main
谢亚昕 5 months ago
parent
commit
c1745e836a
  1. 48
      src/plugins/http/Repeat.ts
  2. 120
      src/plugins/http/base.ts
  3. 110
      src/plugins/http/index.ts
  4. 15
      src/plugins/request.ts
  5. 2
      src/ui/Register/Register.tsx
  6. 17
      src/views/Home/index.tsx

48
src/plugins/http/Repeat.ts

@ -0,0 +1,48 @@
import { isCancel, AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"
import { IPlugin } from "./base"
declare module "axios" {
interface AxiosRequestConfig {
global?: boolean
}
}
// 取消重复请求
export class RepeatPlugin implements IPlugin {
static name: string = "repeat"
name: string = "repeat"
pendingPool = new Map()
clearPendingPool(whiteList: string[] = []) {
if (!this.pendingPool.size) return
const pendingUrlList = Array.from(this.pendingPool.keys()).filter(url => !whiteList.includes(url))
if (!pendingUrlList.length) return
pendingUrlList.forEach(pendingUrl => {
if (!this.pendingPool.get(pendingUrl).global) {
this.pendingPool.get(pendingUrl).cancelFn(`${pendingUrl} 请求取消`)
this.pendingPool.delete(pendingUrl)
}
})
return pendingUrlList
}
beforeRequestConfig({ config }: { config: AxiosRequestConfig }) {
const controller = new AbortController();
config.signal = controller.signal
const cancelFn = (reason?: string) => controller.abort(reason)
this.pendingPool.has(config.url)
? cancelFn(`${config.url} 请求重复`)
: this.pendingPool.set(config.url, { cancelFn, global: config.global })
}
beforeResponse({ response }: { response: AxiosResponse }) {
const { config } = response
this.pendingPool.delete(config.url)
}
beforeResponseError({ error }: { error: AxiosError }) {
const requestConfig = error.config!
if (!isCancel(error)) this.pendingPool.delete(requestConfig.url)
if (!error) return
if (isCancel(error)) {
throw new Error((requestConfig.signal as AbortSignal)?.reason || error.message || `请求'${requestConfig.url}' 被取消`)
}
}
}

120
src/plugins/http/base.ts

@ -1,62 +1,104 @@
import axios, { AxiosInstance, CreateAxiosDefaults } from "axios";
import { deepAssign } from "./utils";
export const enum IHttpMethod {
GET = "GET",
POST = "POST",
DELETE = "DELETE",
PUT = "PUT",
export interface IPlugin {
name: string
created?(...argus: any[]): void
beforeCreate?(...argus: any[]): void
beforeDestory?(...argus: any[]): void
beforeRequestConfig?(...argus: any[]): void
beforeRequestError?(...argus: any[]): void
beforeResponse?(...argus: any[]): void
beforeResponseError?(...argus: any[]): void
destory?(...argus: any[]): void
}
export enum IHttpContentType {
FORM = "application/x-www-form-urlencoded",
JSON = "application/json",
}
class Plugin {
beforeInit() { }
export class Plugin implements IPlugin {
name: string = ""
created() { }
beforeCreate() { }
beforeDestory() { }
beforeRequestConfig() { }
beforeRequestError() { }
beforeResponse() { }
beforeResponseError() { }
destory() { }
}
export abstract class PluginsManager {
static #plugins: Plugin[] = []
static use(plugin: Plugin) {
this.#plugins.push(plugin)
}
callPlugin(key: keyof Plugin, ...argus: any[]) {
PluginsManager.#plugins.forEach(p => p[key].apply(this, argus as []))
static plugins: IPlugin[] = []
static use(plugin: IPlugin) {
if (Array.isArray(plugin)) {
PluginsManager.plugins = this.plugins.concat(plugin)
} else PluginsManager.plugins.push(plugin)
}
}
export abstract class httpBase extends PluginsManager {
static get method() {
return {
GET: "GET",
POST: "POST",
DELETE: "DELETE",
PUT: "PUT",
plugins: IPlugin[] = []
use(plugin: IPlugin) {
if (Array.isArray(plugin)) {
this.plugins = this.plugins.concat(plugin)
} else this.plugins.push(plugin)
}
callPluginByName<T>(name: string, key: keyof T, ...argus: any[]) {
const array = [...PluginsManager.plugins, ...this.plugins]
for (let i = 0; i < array.length; i++) {
let p = array[i]
if (!p.name) continue
if (name === p.name) {
const fn = (p as T)[key]
typeof fn === "function" && fn.apply(p, argus)
}
static get contentType() {
return {
FORM: "application/x-www-form-urlencoded",
JSON: "application/json",
}
}
initDefaultConfig: CreateAxiosDefaults = {
baseURL: process.env.VUE_APP_BASEURL,
timeout: 10000,
headers: {
'Content-Type': httpBase.contentType.FORM,
callPlugin(key: keyof IPlugin, ...argus: any[]) {
const array = [...PluginsManager.plugins, ...this.plugins]
for (let i = 0; i < array.length; i++) {
let p = array[i]
const fn = p[key]
typeof fn === "function" && fn.apply(p, argus)
}
}
}
export abstract class httpBase extends PluginsManager {
instance: AxiosInstance | null = null
requestInterceptorId: null | number = null
responseInterceptorId: null | number = null
create<T>(config?: CreateAxiosDefaults<T>) {
this.instance = axios.create(deepAssign<CreateAxiosDefaults<T>>(axios.defaults, this.initDefaultConfig, config ?? {}))
this.instance = axios.create(deepAssign<CreateAxiosDefaults<T>>(axios.defaults, config ?? {}))
this.requestInterceptorId = this.instance.interceptors.request.use(config => {
const argu = { config }
this.callPlugin("beforeRequestConfig", argu)
return argu.config
}, error => {
const argu = { error }
this.callPlugin("beforeRequestError", argu)
return Promise.reject(error)
})
this.responseInterceptorId = this.instance.interceptors.response.use(response => {
const argu = { response }
this.callPlugin("beforeResponse", argu)
return Promise.resolve(argu.response)
}, (error) => {
const argu = { error }
this.callPlugin("beforeResponseError", argu)
return Promise.reject(error)
})
return this.instance
}
destory() {
// 清理一些事务
if (this.requestInterceptorId) {
this.instance?.interceptors.request.eject(this.requestInterceptorId)
}
if (this.responseInterceptorId) {
this.instance?.interceptors.response.eject(this.responseInterceptorId)
}
httpBase.plugins = []
this.plugins = []
this.instance = null
}
}

110
src/plugins/http/index.ts

@ -1,37 +1,99 @@
import { httpBase, PluginsManager } from "./base"
import { httpBase, IPlugin } from "./base"
import { CreateAxiosDefaults, AxiosRequestConfig, AxiosResponse } from "axios"
import { RepeatPlugin } from "./Repeat"
export const enum IHttpMethod {
GET = "GET",
POST = "POST",
DELETE = "DELETE",
PUT = "PUT",
}
const FlyPoll: Map<string, any> = new Map()
export enum IHttpContentType {
FORM = "application/x-www-form-urlencoded",
JSON = "application/json",
}
class Fly extends httpBase {
static dispose(name: string) {
if (FlyPoll.has(name)) {
const instance = FlyPoll.get(name)
instance.#destory()
FlyPoll.delete(name)
}
}
static init(name: string, config: any, plugins: IPlugin[] = []) {
if (!FlyPoll.has(name)) {
const instance = new Fly(name)
FlyPoll.set(name, instance)
instance.plugins = plugins
instance.#init(config || instance.default)
}
}
static invoke(name?: string): Fly {
if (!name) name = "$defalut"
const instance = FlyPoll.get(name)
if (!instance) throw new Error("未初始化此实例")
return instance
}
static get method() {
return {
GET: "GET",
POST: "POST",
DELETE: "DELETE",
PUT: "PUT",
}
}
const FlyPoll: Map<string, any> = new Map()
static get contentType() {
return {
FORM: "application/x-www-form-urlencoded",
JSON: "application/json",
}
}
class Fly extends httpBase {
constructor() {
default: CreateAxiosDefaults = {
// baseURL: process.env.VUE_APP_BASEURL,
timeout: 10000,
headers: {
'Content-Type': Fly.contentType.FORM,
}
}
name: string
constructor(name: string) {
super()
this.Init()
this.name = name
}
static get(name?: string): Fly {
if (!name) name = "$defalt"
if (!FlyPoll.has(name)) {
FlyPoll.set(name, new Fly())
get(...argus: [url: string, config?: AxiosRequestConfig<unknown> | undefined]) {
return this.instance!.get.apply(this.instance, argus ?? []) as Promise<AxiosResponse>
}
return FlyPoll.get(name)
request(...argus: [config: AxiosRequestConfig<unknown>]): Promise<AxiosResponse> {
return this.instance!.request.apply(this.instance, argus) as Promise<AxiosResponse>
}
Init() {
this.callPlugin("beforeInit")
this.create()
#init(config: AxiosRequestConfig) {
this.callPlugin("beforeCreate")
this.create(config)
this.callPlugin("created")
}
#destory() {
this.callPlugin("beforeDestory")
this.destory()
this.callPlugin("destory")
}
}
Fly.get()
export {
Fly
}
// https://api.52vmy.cn/
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/", global: false }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/wl/yan/bay" }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/img/tu/girl" }).then((res) => console.log(res.data)).catch(console.log)
// setTimeout(()=>{
// // Fly.invoke("empty").request({method: "get", url: "https://api.52vmy.cn/api/img/tu/man"}).then((res)=>console.log(res.data)).catch(console.log)
// Fly.invoke().callPluginByName<RepeatPlugin>(RepeatPlugin.name, "clearPendingPool")
// }, 0)

15
src/plugins/request.ts

@ -0,0 +1,15 @@
import { Fly } from "./http"
import { RepeatPlugin } from "./http/Repeat"
Fly.init("$defalut", {
timeout: 10000,
}, [new RepeatPlugin()])
Fly.init("empty", {
timeout: 10000,
})
export {
Fly
}

2
src/ui/Register/Register.tsx

@ -60,7 +60,7 @@ export function Register({ onSuccess, children }: IProps) {
return (
<>
<form onSubmitCapture={clickRegister}>
<form onSubmit={()=>false} onSubmitCapture={clickRegister}>
<WrapperComp>
<FormGroup helperText="请输入一个可用的邮箱" label="邮箱" labelFor="text-input" labelInfo="(必须)">
<InputGroup

17
src/views/Home/index.tsx

@ -1,18 +1,29 @@
import withPage from "@/base/withPage"
import { Hero } from "@/ui/Hero"
import { ReactNode } from "react"
import { Button } from "@blueprintjs/core"
import { ReactNode, useCallback } from "react"
import { Fly } from "@/plugins/request"
interface IProps {
children: ReactNode
}
export default withPage(function Project({}: IProps) {
export default withPage(function Project({ }: IProps) {
const onClick = useCallback(() => {
Fly.invoke().request({
method: "get",
url: "https://api.52vmy.cn/api/wl/word/bing/tu",
global: false
}).then((res) => console.log(res.data)).catch(console.log)
}, [])
return (
<>
<Hero></Hero>
<div className="container">
<Button onClick={onClick}></Button>
</div>
</>
)

Loading…
Cancel
Save