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

And*_*unn 7 javascript promise vue.js axios es6-modules

我目前正在开展一个项目,为 Udemy 讲师 API 创建客户端。

\n\n

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

\n\n

我将不同的 API 请求抽象为 ES6 化的 API 包装库 ( Udemy.js) 中的函数,以便可以轻松地重用它们。

\n\n

Udemy.js首先初始化 Axios 的实例,然后按照 Promise 导出使用该实例作为基础的 API 函数。

\n\n

下面摘自该文件,但为了便于阅读,我已经删除了模块导出的除其中一个函数之外的所有函数(并且显然编辑了 API 令牌)。端点 URI 包含“message-threadsssss”\xe2\x80\x94,这是故意的,以导致服务器返回 404:

\n\n

\r\n
\r\n
import axios from \'axios\';\r\n\r\nconst token = \'***************************\';\r\nconst axiosOptions = {\r\n  baseURL: \'https://www.udemy.com/instructor-api/v1\',\r\n  timeout: 10000,\r\n  headers: {\r\n    Accept: \'*/*\',\r\n    \'Content-Type\': \'application/json;charset=utf-8\',\r\n    Authorization: `Bearer ${token}`,\r\n  },\r\n};\r\n\r\nconst axiosInstance = axios.create(axiosOptions);\r\n\r\nexport default {\r\n  postMessage(messageThreadId, messageBody) {\r\n    return axiosInstance\r\n            .post(`/message-threadssss/${messageThreadId}/messages/`, {\r\n              content: messageBody,\r\n            })\r\n            .then(response => response.data)\r\n            .catch(error => error);\r\n  },\r\n}
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

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

\n\n

请求发送没有问题,如果请求成功(即 2xx),Vue 组件就能够访问块中的响应数据then()

\n\n

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

\n\n

相反,没有response对象返回并出现错误(情况 2),这使我无法正确处理它。当请求确实导致服务器响应 404 错误时,就会发生这种情况:

\n\n
HTTP/2.0 404 Not Found\ncontent-type: text/json\n
Run Code Online (Sandbox Code Playgroud)\n\n

我读过,如果 Axios 应用了拦截器,可能会导致此问题,但在这种情况下,我没有应用任何拦截器。

\n\n

总而言之,我有点不知所措。如何将服务器的响应获取到我的 Vue 组件中?

\n\n

编辑(2月6日)

\n\n

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

\n\n
12:22:28.748\nXMLHttpRequest\n    mozAnon: false\n    mozSystem: false\n    onabort: null\n    onerror: function handleError()\n    onload: null\n    onloadend: null\n    onloadstart: null\n    onprogress: null\n    onreadystatechange: function handleLoad()\n    ontimeout: function handleTimeout()\n    readyState: 4\n    response: ""\n    responseText: ""\n    responseType: ""\n    responseURL: ""\n    responseXML: null\n    status: 0\n    statusText: ""\n    timeout: 100000\n    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, \xe2\x80\xa6 }\n    withCredentials: false\n    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), \xe2\x80\xa6 }\nreplybox.vue:72\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑2(2月6日)

\n\n

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

\n\n
 postMessage(messageThreadId, messageBody) {\n    return axiosInstance\n            .post(`/message-threadssss/${messageThreadId}/messages/`, {\n              content: messageBody,\n            });\n  },\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

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

控制台输出:

\n\n
12:38:51.888 Error: "Network Error"\n    createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15\n    handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14\nreplybox.vue:62\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑 3(1 月 6 日)

\n\n

我意识到在之前的编辑中,我在定义中省略了error.requestafter I\d.then和 的输出。如果我重新添加到组件中的调用块,则输出如下:.catchpostMessageconsole.log(error.request);.catch

\n\n
12:58:55.436\nXMLHttpRequest\n    mozAnon: false\n    mozSystem: false\n    onabort: null\n    onerror: function handleError()\n    onload: null\n    onloadend: null\n    onloadstart: null\n    onprogress: null\n    onreadystatechange: function handleLoad()\n    ontimeout: function handleTimeout()\n    readyState: 4\n    response: ""\n    responseText: ""\n    responseType: ""\n    responseURL: ""\n    responseXML: null\n    status: 0\n    statusText: ""\n    timeout: 100000\n    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, \xe2\x80\xa6 }\n    withCredentials: false\n    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), \xe2\x80\xa6 }\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑4(2月6日)

\n\n

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

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

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

\n\n

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

\n\n
13:25:45.783 Error obj:  Error: "Network Error"\n    createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15\n    handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14\nreplybox.vue:79\n\n13:25:45.786 Request error obj:  \nXMLHttpRequest\n    mozAnon: false\n    mozSystem: false\n    onabort: null\n    onerror: function handleError()\n    onload: null\n    onloadend: null\n    onloadstart: null\n    onprogress: null\n    onreadystatechange: function handleLoad()\n    ontimeout: function handleTimeout()\n    readyState: 4\n    response: ""\n    responseText: ""\n    responseType: ""\n    responseURL: ""\n    responseXML: null\n    status: 0\n    statusText: ""\n    timeout: 100000\n    upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, \xe2\x80\xa6 }\n    withCredentials: false\n    <prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), \xe2\x80\xa6 }\nreplybox.vue:80\n
Run Code Online (Sandbox Code Playgroud)\n

And*_*unn 3

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

因此,Axios 无法访问响应。

目前,我需要解决一个一般性的模糊错误,但未来的解决方案取决于为 CORS 提供成功和错误响应的 API 开发人员。

非常感谢Bergi的帮助,最终让我找到了问题的原因。