在 Vue 项目中使 axios 全局化不起作用

Posted

技术标签:

【中文标题】在 Vue 项目中使 axios 全局化不起作用【英文标题】:Making axios global in Vue project is not working 【发布时间】:2019-12-15 23:41:36 【问题描述】:

直到现在,我一直在我想发出 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 unauthorized 响应并注销用户。 到目前为止我的理解是你必须实例化 axios 一次并在任何地方使用它,而不是在每个文件中导入和使用不同的实例。

我参考了this 和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);

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 是组件本身,但我不确定)。我该如何解决这个问题?

[UPDATE]感谢回复,我决定在单独的文件中初始化 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);
  

【问题讨论】:

你为什么不试试github.com/imcvampire/vue-axios? 你不能在application.js中写this.$http.interceptors,你需要使用axios.interceptors。如果这不是您的问题的原因,您能否更新您的问题,以包括对 put 的呼叫不起作用。没有一些上下文,很难判断你是否正确地做到了这一点。 @skirtle 我将我对 axios 实例的引用更改为 axios,但是当我尝试在任何其他文件中调用它时,它仍然会出现“属性 '$http' 在类型'ExamplePage 上不存在' '(组件名称)”。正如我在上面所写的,这可能是因为该组件上下文中的this 指的是组件本身。进一步的建议表示赞赏。 自从我上次查看以来,问题似乎发生了重大变化,现在在 TypeScript 中。当问题变化如此之大时,很难给出任何答案。在您的最新代码中,您有const status = error.response;,它可能应该是const status = error.response.status;。错误处理程序也没有返回被拒绝的承诺,这可能证明是有问题的。 【参考方案1】:

不能直接解决您的问题,但我创建 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'

【讨论】:

【参考方案2】:

当你不在 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>

【讨论】:

当我尝试在任何组件文件中使用this.$http 时,它会显示“ 类型上不存在属性'$http'”。不知何故,Vue.prototype 似乎在这里不起作用。【参考方案3】:

我遇到了同样的问题。 在 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 Documentation - Interceptors section看到

【讨论】:

【参考方案4】:

我建议你在单独的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 实例都使用拦截器的问题。【参考方案5】:

尝试实现一个服务:

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) 
    );

【讨论】:

以上是关于在 Vue 项目中使 axios 全局化不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Axios 授权不起作用 - VueJS + Django

Axios删除不起作用

Axios 请求拦截器在我的 vue 应用程序中不起作用

由于缺乏对纹理坐标的理解,场景体素化不起作用

现在的vue-axios全局安装?

如何将axios全局导入vue.js项目[重复]