我有一个 Vue 插件,用于创建 axios 实例,我想将其用于所有 api 调用。
插件/axios.ts
import axios from 'axios'
import type { App } from 'vue'
interface AxiosOptions {
baseUrl: string
}
function isIsoDateString(value: any): boolean {
...
}
function handleDates(body: any) {
...
}
export default {
install: (app: App, options: AxiosOptions) => {
const axiosInstance = axios.create({
baseURL: options.baseUrl,
headers: {
"Accept": "application/json",
"Content-type": "application/json"
}
});
axiosInstance.interceptors.response.use(originalResponse => {
handleDates(originalResponse.data);
return originalResponse;
});
app.provide("axios", axiosInstance);
}
}
此插件随后会在 createApp 调用中添加到应用程序中:
main.ts
import { createApp } from "vue";
import { createPinia } from "pinia";
import mitt from "mitt";
import axios from "@/plugins/axios";
import App from "./App.vue"
import router from "./router";
const emitter = mitt();
const app = createApp(App)
.use(router)
.use(createPinia())
.use(axios, {baseUrl: "http://localhost:15454/"});
app.provide("emitter", emitter);
app.mount("#app");
在我的 api 调用中,我只是这样使用它:
actions/providers.ts
import { inject } from 'vue'
import type { AxiosInstance } from 'axios';
import { type Provider } from "../types/Provider";
export const getProviders = async (activeOnly: boolean): Promise<Provider[]> => {
const ax = inject('axios') as AxiosInstance;
try {
const response = await ax.get(`/Provider/${activeOnly}`);
return response.data;
} catch (error) {
...
return [];
}
};
当在设置期间调用 api 时,此方法有效。 但是,我收到错误
inject() 只能在 setup() 或函数组件内部使用。
当从事件处理程序发起 api 调用时,例如。
<script setup lang="ts">
const handleClick = async () => {
const value = await getProviders(true);
}
</script>
<template>
<button @click="handleClick">Submit</button>
</template>
为什么事件处理程序会发生这种情况?我需要做什么才能以这种方式使用axios?
由于 axios baseURL 是在单独的配置文件中定义的,因此解决方案变得复杂。
我使用插件来读取配置文件 - 这使得配置选项可供应用程序使用: runtimeConfig.ts
import type {App, Plugin} from 'vue';
export type RuntimeConfigType = {
apiUrl: string,
uploadMaxFilesize: number
};
export interface RuntimeConfigOptions {
values: RuntimeConfigType
};
export const loadRuntimeConfig = async (): Promise<RuntimeConfigOptions> => {
const resp = await fetch('/config.json');
const value = await resp.json();
return {
values: {
apiUrl: value.API_URL,
uploadMaxFilesize: value.UPLOAD_MAX_FILE_SIZE
} as RuntimeConfigType
} as RuntimeConfigOptions
};
export const runtimeConfig: Plugin = {
install: (app: App, options: RuntimeConfigOptions) => {
app.config.globalProperties.$runtimeConfig = options.values;
app.provide("runtimeConfig", options.values);
}
};
将插件添加到应用程序:main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { loadRuntimeConfig, runtimeConfig } from "@/plugins/runtimeConfig";
import { useAxios } from "@/composables/useAxios";
const RuntimeConfigOptions = await loadRuntimeConfig();
// Make config options available in non-component files - for service implementation (https://stackoverflow.com/questions/73917711/vue3-use-global-variable-in-js-files)
// export const useRuntimeConfig = () => RuntimeConfigOptions;
const { initialise } = useAxios();
initialise(RuntimeConfigOptions.values.apiUrl);
const app = createApp(App);
app.use(router);
app.use(runtimeConfig, RuntimeConfigOptions);
app.mount("#app");
最后,axios 被包装在一个可组合项中(我也使用类实例将其作为服务来完成 - 首选可组合项):useAxios.ts
import axios, { type AxiosInstance } from "axios";
const instance: AxiosInstance = axios.create({
headers: {
"Accept": "application/json",
"Content-type": "application/json"
},
});
export function useAxios() {
const initialise = (baseURL: string) => {
instance.defaults.baseURL = baseURL;
instance.interceptors.response.use(originalResponse => {
handleDates(originalResponse.data);
return originalResponse;
});
}
function isIsoDateString(value: any): boolean {...};
function handleDates(body: any) {...};
return { initialise, instance }
}
使用时只需导入可组合项、解构并调用 axios 方法:
import { useAxios } from "@/composables/useAxios";
const { instance } = useAxios();
const response = await instance.get(someurl);
为了完整起见,这是 axios 的服务(类)版本:http.cs
import axios, { type AxiosInstance } from "axios";
import type { RuntimeConfigOptions } from "@/plugins/runtimeConfig";
import { useRuntimeConfig } from "@/main";
export default new class http {
axiosInstance: AxiosInstance = axios.create({
headers: {
"Accept": "application/json",
"Content-type": "application/json"
},
});
constructor() {
this.axiosInstance.interceptors.response.use(originalResponse => {
this.handleDates(originalResponse.data);
return originalResponse;
});
}
isIsoDateString(value: any): boolean {...};
handleDates(body: any) {...};
instance() {
const { values } = useRuntimeConfig() as RuntimeConfigOptions;
this.axiosInstance.defaults.baseURL = values.apiUrl;
return this.axiosInstance;
}
};