在Vue 3中使用Axios实例

问题描述 投票:0回答:1

我有一个 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 vuejs3 vue-composition-api
1个回答
0
投票

由于 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;
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.