为什么我的Axios实例未在捕获到的错误中返回响应?

时间:2019-02-05 18:31:43

标签: javascript vue.js promise axios es6-modules

我目前正在为Udemy教练API创建客户端的项目。

我已经使用Axios作为HTTP客户端在Vue中编写了客户端。

我已将不同的API请求抽象到ES6标准化的API包装器库(Udemy.js)中的函数中,以使其易于重用。

Udemy.js首先初始化Axios的实例,然后导出使用API​​实例作为承诺的基础的API函数。

下面是从文件中摘录的,尽管为了方便阅读,我删除了模块导出的所有功能,但仅删除了其中一个功能(并且显然删除了API令牌)。端点URI包含“ message-threadsssss”,这是有意的,导致服务器返回404:

import axios from 'axios';

const token = '***************************';
const axiosOptions = {
  baseURL: 'https://www.udemy.com/instructor-api/v1',
  timeout: 10000,
  headers: {
    Accept: '*/*',
    'Content-Type': 'application/json;charset=utf-8',
    Authorization: `Bearer ${token}`,
  },
};

const axiosInstance = axios.create(axiosOptions);

export default {
  postMessage(messageThreadId, messageBody) {
    return axiosInstance
            .post(`/message-threadssss/${messageThreadId}/messages/`, {
              content: messageBody,
            })
            .then(response => response.data)
            .catch(error => error);
  },
}

UdemyApi.postMessage(threadId, threadReply);
.then((response) => {
        this.isLoading = false;
        this.sentReply = response;
        this.replyBody = '';
        this.$root.$emit('reply-sent', {
          threadId: this.thread.id,
          sentReply: this.sentReply,
        });
      })
      .catch((error) => {
        if (error.response) {
          // Case 1 (Server returned error)
          console.log(error.response.data);
          console.log(error.response.status);
          console.log(error.response.headers);
        } else if (error.request) {
          // Case 2 (Pre-response error)
          console.log(error.request);
        } else {
          // Case 3 (Mysterious error)
          console.log('Error:', error.message);
        }
        this.$root.$emit('show-snackbar', {
          message: `Failed to send. ${error} `,
          actionText: 'Understood. :(',
        });
        this.isLoading = false;
      });

请求发送没有问题,如果请求成功(例如2xx),则Vue组件可以访问then()块中的响应数据。

当服务器返回错误(在这种情况下为404)时,我希望捕获的错误包含一个response对象(案例1)。

尽管如此,但没有返回任何带有错误的response对象(情况2),这使我无法正确处理它。当请求确实导致服务器响应404错误时,就会发生这种情况:

HTTP/2.0 404 Not Found
content-type: text/json

我已经阅读到,如果Axios对其应用了拦截器,则可能导致此问题,但是在这种情况下,我没有应用任何拦截器。

总而言之,我有点茫然。如何将服务器的响应传递到我的Vue组件中?

编辑(2月6日)

我在最初的帖子中没有包含所有有用的控制台输出,所以就在这里。执行的console.log()行是案例2的行(仅添加了一个控制台日志条目,而不像案例3那样带有“ Error:”作为前缀):

12:22:28.748
XMLHttpRequest
    mozAnon: false
    mozSystem: false
    onabort: null
    onerror: function handleError()
    onload: null
    onloadend: null
    onloadstart: null
    onprogress: null
    onreadystatechange: function handleLoad()
    ontimeout: function handleTimeout()
    readyState: 4
    response: ""
    responseText: ""
    responseType: ""
    responseURL: ""
    responseXML: null
    status: 0
    statusText: ""
    timeout: 100000
    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
    withCredentials: false
    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }
replybox.vue:72

编辑2(2月6日)

如果我从then()定义中删除catch()postMessage()看起来像这样:

 postMessage(messageThreadId, messageBody) {
    return axiosInstance
            .post(`/message-threadssss/${messageThreadId}/messages/`, {
              content: messageBody,
            });
  },

然后简化catch()调用的postMessage()块,以仅输出error对象,如下所示:

    .catch((error) => {
        console.log(error);
        this.$root.$emit('show-snackbar', {
          message: `Failed to send. ${error} `,
          actionText: 'Understood. :(',
        });
        this.isLoading = false;
      });

控制台输出:

12:38:51.888 Error: "Network Error"
    createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15
    handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14
replybox.vue:62

编辑3(1月6日)

我在上一次编辑中意识到,在从error.request定义中删除了.then.catch之后,我省略了postMessage的输出。如果我将console.log(error.request);重新添加到组件中调用的.catch块中,则输出为:

12:58:55.436
XMLHttpRequest
    mozAnon: false
    mozSystem: false
    onabort: null
    onerror: function handleError()
    onload: null
    onloadend: null
    onloadstart: null
    onprogress: null
    onreadystatechange: function handleLoad()
    ontimeout: function handleTimeout()
    readyState: 4
    response: ""
    responseText: ""
    responseType: ""
    responseURL: ""
    responseXML: null
    status: 0
    statusText: ""
    timeout: 100000
    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
    withCredentials: false
    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }

编辑4(2月6日)

要确认或排除我对API抽象层的实现,我直接在组件中调用了一个Axios实例:

const token = '*********************';
const axiosOptions = {
  baseURL: 'https://www.udemy.com/instructor-api/v1',
  timeout: 100000,
  headers: {
    Accept: '*/*',
    'Content-Type': 'application/json;charset=utf-8',
    Authorization: `Bearer ${token}`,
  },
};
const axiosInstance = axios.create(axiosOptions);
axiosInstance
.post(`/message-threadssss/${this.thread.id}/messages/`, {
  content: this.replyBody,
})
.then((response) => {
  this.isLoading = false;
  this.sentReply = response;
  this.replyBody = '';
  this.$root.$emit('reply-sent', {
    threadId: this.thread.id,
    sentReply: this.sentReply,
  });
})
.catch((error) => {
  console.log('Error obj: ', error);
  console.log('Request error obj: ', error.request);
  this.$root.$emit('show-snackbar', {
    message: `Failed to send. ${error} `,
    actionText: 'Understood. :(',
  });
  this.isLoading = false;
  this.axiosResult = error;
});

和以前一样,服务器返回了预期的404,而我组件中的.catch块捕获了错误。

和以前一样,捕获的错误中缺少响应

13:25:45.783 Error obj:  Error: "Network Error"
    createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15
    handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14
replybox.vue:79

13:25:45.786 Request error obj:  
XMLHttpRequest
    mozAnon: false
    mozSystem: false
    onabort: null
    onerror: function handleError()
    onload: null
    onloadend: null
    onloadstart: null
    onprogress: null
    onreadystatechange: function handleLoad()
    ontimeout: function handleTimeout()
    readyState: 4
    response: ""
    responseText: ""
    responseType: ""
    responseURL: ""
    responseXML: null
    status: 0
    statusText: ""
    timeout: 100000
    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
    withCredentials: false
    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }
replybox.vue:80

2 个答案:

答案 0 :(得分:1)

我很确定您需要做的就是从.then函数中删除.catchpostMessage,您应该一切顺利

postMessage(messageThreadId, messageBody) {
  return axiosInstance
     .post(`/message-threadssss/${messageThreadId}/messages/`, {
        content: messageBody,
      })
}

这样,postMessage返回了一个承诺。当您实际致电postMessage时,可以使用.then.catch

答案 1 :(得分:0)

所以,答案似乎实际上是我调用的API的结果,该API没有为错误响应提供正确的CORS标头(因此,仅允许2xx响应使用CORS)。

因此,Axios无法访问响应。

目前,我需要解决一个普遍的模棱两可的错误,但是解决方案要靠为CORS提供成功和错误响应的API开发人员来解决。

非常感谢Bergi的帮助,最终使我找到了问题的根源。