为什么我的 Axios 实例没有 return 捕获错误的响应?
Why does my instance of Axios not return the response in a caught error?
我目前正在进行一个项目,为 Udemy 讲师创建客户端 API。
我用 Vue 编写了客户端,使用 Axios 作为我的 HTTP 客户端。
我已将不同的 API 请求抽象为 ES6 化的 API 包装器库 (Udemy.js
) 中的函数,以便于重用它们。
Udemy.js
首先初始化一个 Axios 实例,然后导出 API 使用该实例作为基础的函数作为承诺。
下面是从文件中提取的,尽管为了便于阅读,我已经删除了模块导出的所有功能,除了一个功能(并且显然编辑了 API 标记)。端点 URI 包含 "message-threadssss" — 这是故意的,目的是让服务器 return 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()
块中的响应数据。
当服务器 return 出现错误(在本例中为 404)时,我希望捕获的错误包含一个 response
对象(案例 1)。
相反,没有 response
对象被 return 编辑错误(案例 2),这使我无法正确处理它。当请求确实导致服务器响应 404 错误时,就会发生这种情况:
HTTP/2.0 404 Not Found
content-type: text/json
我读到如果 Axios 应用了拦截器,可能会导致这个问题,但在这种情况下,我没有应用任何拦截器。
总而言之,我有点不知所措。如何让服务器的响应进入我的 Vue 组件?
编辑(2 月 6 日)
我没有在我的初始 post 中包含所有有用的控制台输出,所以在这里。执行的 console.log() 行是案例 2 行(只添加了一个控制台日志条目,没有前缀 "Error: ",就像案例 3 中的情况一样):
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 日)
如果我从 postMessage()
定义中删除 then()
和 catch()
如下所示:
postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
});
},
然后简化 postMessage()
调用的 catch()
块,只输出 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 日)
我在之前的编辑中意识到,在我从 postMessage
定义中删除 .then
和 .catch
后,我省略了 error.request
的输出。如果我将 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;
});
和以前一样,服务器 returned 了预期的 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
我很确定您需要做的就是从 postMessage
函数中删除 .then
和 .catch
,您应该可以开始了
postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
})
}
这样,postMessage
返回一个承诺。当您实际调用 postMessage
时,您可以使用 .then
和 .catch
所以,看起来的答案实际上是 API 我打电话的结果是没有提供正确的 CORS headers 错误响应(因此 CORS 只允许 2xx 响应)。
因此,Axios 无法访问响应。
目前我需要解决一个普遍的模棱两可的错误,但未来的解决方案取决于 API 为 CORS 提供成功和错误响应的开发人员。
非常感谢 Bergi 的帮助,最终让我找到了问题的根源。
我目前正在进行一个项目,为 Udemy 讲师创建客户端 API。
我用 Vue 编写了客户端,使用 Axios 作为我的 HTTP 客户端。
我已将不同的 API 请求抽象为 ES6 化的 API 包装器库 (Udemy.js
) 中的函数,以便于重用它们。
Udemy.js
首先初始化一个 Axios 实例,然后导出 API 使用该实例作为基础的函数作为承诺。
下面是从文件中提取的,尽管为了便于阅读,我已经删除了模块导出的所有功能,除了一个功能(并且显然编辑了 API 标记)。端点 URI 包含 "message-threadssss" — 这是故意的,目的是让服务器 return 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()
块中的响应数据。
当服务器 return 出现错误(在本例中为 404)时,我希望捕获的错误包含一个 response
对象(案例 1)。
相反,没有 response
对象被 return 编辑错误(案例 2),这使我无法正确处理它。当请求确实导致服务器响应 404 错误时,就会发生这种情况:
HTTP/2.0 404 Not Found
content-type: text/json
我读到如果 Axios 应用了拦截器,可能会导致这个问题,但在这种情况下,我没有应用任何拦截器。
总而言之,我有点不知所措。如何让服务器的响应进入我的 Vue 组件?
编辑(2 月 6 日)
我没有在我的初始 post 中包含所有有用的控制台输出,所以在这里。执行的 console.log() 行是案例 2 行(只添加了一个控制台日志条目,没有前缀 "Error: ",就像案例 3 中的情况一样):
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 日)
如果我从 postMessage()
定义中删除 then()
和 catch()
如下所示:
postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
});
},
然后简化 postMessage()
调用的 catch()
块,只输出 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 日)
我在之前的编辑中意识到,在我从 postMessage
定义中删除 .then
和 .catch
后,我省略了 error.request
的输出。如果我将 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;
});
和以前一样,服务器 returned 了预期的 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
我很确定您需要做的就是从 postMessage
函数中删除 .then
和 .catch
,您应该可以开始了
postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
})
}
这样,postMessage
返回一个承诺。当您实际调用 postMessage
时,您可以使用 .then
和 .catch
所以,看起来的答案实际上是 API 我打电话的结果是没有提供正确的 CORS headers 错误响应(因此 CORS 只允许 2xx 响应)。
因此,Axios 无法访问响应。
目前我需要解决一个普遍的模棱两可的错误,但未来的解决方案取决于 API 为 CORS 提供成功和错误响应的开发人员。
非常感谢 Bergi 的帮助,最终让我找到了问题的根源。