The key distinction between a request error and a response error lies in their sequence within the promise chain constructed by the interceptors. Refer to this source code
// implementing interceptors
forEach(reversedInterceptors, function(interceptor) {
if (interceptor.request || interceptor.requestError) {
chain.unshift(interceptor.request, interceptor.requestError);
}
if (interceptor.response || interceptor.responseError) {
chain.push(interceptor.response, interceptor.responseError);
}
});
while (chain.length) {
var thenFn = chain.shift();
var rejectFn = chain.shift();
promise = promise.then(thenFn, rejectFn);
}
Therefore, when using interceptors that offer all four methods, the resulting promise will follow this pattern:
promise.then(requestFn, requestErrorFn).then(responseFn, responseErrorFn)
.
In regards to point 2., the promise is generated through var promise = $q.when(config);
once a request has been initialized. Initially, understanding the process may seem complex, but it appears that the config object contains default callbacks. If there are issues with the request syntax or configuration, or Angular faces difficulties sending the request (such as no network connection), the original promise would resolve as rejected, triggering the invocation of the requestError
handler.