在Vue项目中全局使用axios无效。

4

到目前为止,我一直在每个想要进行HTTP请求的Vue组件中导入axios,就像这样。

<script lang="ts">
import axios from 'axios';

@Component
export default class ExamplePage extends Vue {
  created(): void {
    axios.post(some_path);
  }
}

然而,现在我想为所有 axios 请求定义一个全局拦截器,基本上是为了捕获后端服务器(Rails)返回的所有401未授权响应并注销用户。 我目前的理解是您必须实例化 axios 一次并在各处使用它,而不是在每个文件中导入和使用不同的实例。
我参考了这个这个,并尝试了以下方法。
// application.js

import '../assets/sass/base.sass';
import App from '../app';
import Vue from 'vue';
import VueRouter from 'vue-router';
import axios from 'axios';
import router from '../routes';

Vue.use(VueRouter);

document.addEventListener('DOMContentLoaded', () => {
  new Vue({
    el: '#application',
    router,
    render: (h) => h(App),
  });
});

axios.interceptors.response.use(
  response => response,
  error => {
    const status = error.response;
    if(status === 401) {
      // do stuff
    }
  }
);

Vue.prototype.$http = axios

当我尝试在另一个文件中调用this.$http.put(...)时,它显示属性$http不存在(我猜测这是因为那个组件上下文中的this是组件本身,但我不确定)。我该如何解决这个问题? [更新] 感谢您的回复,我决定在一个单独的文件中初始化axios实例,然后使用它。然而,这仍然无法正常工作。401响应似乎根本没有触发拦截器。
是否需要进行其他配置?
// axios-instance.ts
import axios, { AxiosInstance } from 'axios';

const axiosInstance: AxiosInstance = axios.create();

axiosInstance.interceptors.response.use(
  response => response.data,
  async function(error) {
    console.log("THIS IS THE 401 INTERCEPTOR")
    const status = error.response;
    if(status === 401) {
      // Log out user
    }
  }
);

export default axiosInstance;


// Some component
<script lang="ts">
import axiosInstance from 'axios-instance';

@Component
export default class ExamplePage extends Vue {
  created(): void {
    axiosInstance.post(some_path);
  }
}

为什么不尝试使用 https://github.com/imcvampire/vue-axios? - Bilal Budhani
你不能在 application.js 中写 this.$http.interceptors,必须使用 axios.interceptors。如果这不是问题的原因,请更新您的问题以包含未正常工作的 put 调用。没有一些上下文,很难确定您是否正确执行了这个操作。 - skirtle
@skirtle,我将axios实例的引用更改为“axios”,但是当我尝试在任何其他文件中调用它时,它仍然会出现“在类型'ExamplePage'(组件名称)上不存在属性'$http'”。正如我上面所写的那样,这可能是因为该组件上下文中的“this”指向组件本身。欢迎进一步建议。 - reesaspieces
自从我上次查看以来,问题似乎已经发生了很大的变化,现在是TypeScript。当问题如此之大时,很难给出任何答案。在您最新的代码中,您有const status = error.response;,这应该是const status = error.response.status;。错误处理程序也没有返回拒绝的承诺,这可能会带来问题。 - skirtle
5个回答

8

虽然不能直接解决你的问题,但我创建 axios 实例的方式是:

// axios-instance.js

import axios from 'axios'

const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});

export default instance

在导入实例后

// application.js

import axios from '../../axios-instance'


3
您不可以在Vue实例之外使用this。请尝试以下方法:
// application.js

import '../assets/sass/base.sass';
import App from '../app';
import Vue from 'vue';
import VueRouter from 'vue-router';
import axios from 'axios';
import router from '../routes';

Vue.use(VueRouter);

axios.interceptors.response.use(
  response => response,
  error => {
    const status = error.response;
    if(status === 401) {
      // do stuff
      }
    }
  }
);

Vue.prototype.$http = axios;

const VueInstance = new Vue({
    el: '#application',
    router,
    render: (h) => h(App),
});

现在您可以使用this.$http进行HTTP请求:

<script>
    export default {
        methods: {
            doStuff() {
                this.$http.post('path_to_post_request').then(({ data }) => {
                    // do something with received data
                }).catch((e) => {});
            }
        }
    }
</script>

1
当我尝试在任何组件文件中使用this.$http时,它会显示“属性'$http'在类型<组件名称>上不存在”。不知何故,似乎Vue.prototype在这里无法正常工作。 - reesaspieces

1

尝试实现一个服务:

src/services/yourservice.js

import axios from 'axios'

const apiClient = axios.create({
    baseURL: 'https://example.com/api',
    withCredentials: false,
    timeout: 1000,
   
    headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        'Authorization': 'Basic ' + btoa('api_username_here' + ':' + 'api_password_here')     
    }
})

export default {
    getOrders(){
        return apiClient.get('/orders?status=processing')
    },
    getProducts(id){
        return apiClient.get('/products/' + id)
    },
}

在组件中使用该服务: src / component / yourcomponent.vue

import YourService from '@/services/YourService.js';
data() {
    return {
        orders: null, //Typescript
    }
},
created() {
    yourservice.getOrder(id).then(response => {
        this.orders = response.data 
    }).catch(error => {
        console.log(error) 
    });
}

1
我建议您在单独的js文件中实现axios实例:
// utils/request.js

import axios from 'axios'

const service = axios.create({
  baseURL: '',
  headers: {},
  withCredentials: true,
  // ...other options
})

// request interceptor
service.interceptors.request.use(config => {
  // ...
  return config
}, err => {
  return Promise.reject(err)
})

// response interceptor
service.interceptors.response.use(response => {
  // ...
  return response
}, err => {
  return Promise.reject(err)
})

export default service

然后您可以像这样使用HTTP请求:

import request from '@/utils/request'

request({
  url: '',
  method: 'post',
  data: {}
}).then(res => {
  // Do something after the request is successful
}).catch(err => {
  // Do something after the request fails
})

你好,能否看一下我上面的更新?我按照你的评论尝试了,但是仍然存在所有axios实例使用拦截器的问题。 - reesaspieces

1
我遇到了同样的问题。 在Axios API文档中,并没有明确说明错误响应应该在响应拦截器的错误回调中被拦截。
应该像这样做:
axios.interceptors.response.use(function (response) {
  //This is the success callback in case u ever need it
  return response;
}, function (error) {
  // This is the callback I was talking about.
  // Do something with request error
  // Tip: error.response is the actual response with error code
  return Promise.reject(error);
})

这可以在 Axios API文档 - 拦截器部分中看到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接