Angular2 Запрос REST HTTP-код состояния 401 изменяется на 0
Я разрабатываю приложение Angular2. Кажется, что, когда мой токен доступа истекает, код статуса 401 HTTP изменяется в значение 0 в объекте Response. Я получаю 401 Unauthorized, но объект ответа ERROR имеет статус 0. Это мешает мне захватить ошибку 401 и попытаться обновить токен. Что заставляет код статуса 401 HTTP быть изменен в код состояния HTTP 0?
Вот скриншот из консоли Firefox:
![введите описание изображения здесь]()
Здесь мой код:
get(url: string, options?: RequestOptionsArgs): Observable<any>
{
//console.log('GET REQUEST...', url);
return super.get(url, options)
.catch((err: Response): any =>
{
console.log('************* ERROR Response', err);
if (err.status === 400 || err.status === 422)
{
return Observable.throw(err);
}
//NOT AUTHENTICATED
else if (err.status === 401)
{
this.authConfig.DeleteToken();
return Observable.throw(err);
}
else
{
// this.errorService.notifyError(err);
// return Observable.empty();
return Observable.throw(err);
}
})
// .retryWhen(error => error.delay(500))
// .timeout(2000, new Error('delay exceeded'))
.finally(() =>
{
//console.log('After the request...');
});
}
Этот код находится в пользовательской службе http, которая расширяет Angular2 HTTP, поэтому я могу перехватывать ошибки в одном месте.
В Google Chrome я получаю следующее сообщение об ошибке:
XMLHttpRequest не может загрузить https://api.cloudcms.com/repositories/XXXXXXXXXXXXXXXX/branches/XXXXXXXXXXXXXXXX/nodesXXXXXXXXXXXXXXXX. В запрошенном ресурсе нет заголовка "Access-Control-Allow-Origin". Origin 'http://screwtopmedia.local.solutiaconsulting.com', следовательно, не допускается. В ответе был код статуса HTTP 401.
Это запутанно, потому что я включаю заголовок "Access-Control-Allow-Origin" в запросе.
Вот изображение результатов, полученных в Google Chrome:
![введите описание изображения здесь]()
Я попытался получить доступ к заголовку ответа WWW-Authenticate в качестве средства для ловушки для 401. Однако следующий код возвращает NULL:
err.headers.get("WWW-Authenticate")
Непонятно, что я получаю проблему CORS, потому что я не получаю ошибок CORS, когда предоставляется действительный токен доступа.
Как мне ловушка для кода состояния 401 HTTP? Почему 401 код статуса HTTP изменяется на 0?
Спасибо за вашу помощь.
Ответы
Ответ 1
Я работаю для Cloud CMS. Я могу подтвердить, что мы правильно настроили заголовки CORS для вызовов API. Однако для 401 ответов заголовки не устанавливаются должным образом. Это было решено, и исправление будет доступно в публичном API в конце этой недели.
Кстати, если вы используете наш javascript-драйвер https://github.com/gitana/gitana-javascript-driver вместо того, чтобы напрямую писать в API, то поток re-auth обрабатывается автоматически, и вы не нужно ломать ошибки 401.
Ответ 2
Эта проблема связана с запросами CORS, см. Эту проблему в github.
В запрошенном ресурсе отсутствует заголовок "Access-Control-Allow-Origin"
означает, что в заголовках ответа требуется 'Access-Control-Allow-Origin'
.
Angular не получает никаких кодов состояния, поэтому он дает 0
что вызвано тем, что браузер не позволяет xml parser
анализировать response
из-за неправильных headers
.
Вам необходимо добавить правильные заголовки CORS к вашему error response
а также к success
.
Ответ 3
Если cloudcms.com не устанавливает Access-Control-Allow-Origin
в ответе 401, то вы ничего не можете сделать. Вы должны правильно открыть билет поддержки с ними, чтобы подтвердить, если это нормальное поведение.
javascript в браузерах (FF, Chrome & Safari), которые я тестировал, не получит никакой информации, если произойдет ошибка CORS, кроме статуса 0. Angular2 не контролирует ее.
Я создал простой тест и получаю тот же результат, что и ваш:
geturl() {
console.log('geturl() clicked');
let headers = new Headers({ 'Content-Type': 'application/xhtml+xml' });
let options = new RequestOptions({ 'headers': headers });
this.http.get(this.url)
.catch((error): any => {
console.log('************* ERROR Response', error);
let errMsg = (error.message) ? error.message :
error.status ? '${error.status} - ${error.statusText}' : 'Web Server error';
return Observable.throw(error);
})
.subscribe(
(i: Response) => { console.log(i); },
(e: any) => { console.log(e); }
);
}
После долгих поисков я обнаружил следующее (https://github.com/angular/angular.js/issues/3336):
lucassp прокомментировал 19 августа 2013
Я нашел проблему на некоторое время, но я забыл опубликовать здесь ответ. КАЖДЫЙ ответ, даже Ошибка 500, должен иметь присоединенные заголовки CORS. Если сервер не присоединяет заголовки CORS к ответу об ошибке 500, то объект XHR не будет его анализировать, поэтому у объекта XHR не будет тела ответа, статуса или каких-либо других данных ответа внутри.
Результат от сетевого монитора Firefox, кажется, поддерживает вышеуказанную причину.
Javascript запрос получит пустой ответ. ![javascript request]()
Простой запрос URL (скопируйте и вставьте ссылку в адресную строку) получит тело ответа ![Plain url request]()
Javascript использует XHRHttpRequest для http-связи.
Когда приходит ответ XHR, браузер обработает заголовок, поэтому вы увидите эти 401 сетевые сообщения. Однако, если XHR-ответ получен от другого хоста, тогда javascript И заголовок ответа не содержат заголовок CORS (например, Access-Control-Allow-Origin: *
), браузер не будет передавать какую-либо информацию обратно на уровень XHR. В результате тело ответа будет полностью пустым без статуса (0).
Я тестировал с FF 48.0.1, Chrome 52.0.2743.116 и Safari 9.1.2, и все они ведут себя одинаково.
Используйте сетевой монитор браузера, чтобы проверить заголовок ответа для этих 401 Unauthorized
записей, очень вероятно, что нет заголовка Access-Control-Allow-Origin
и вызывающего проблему, с которой вы столкнулись. Это может быть ошибка или дизайн на стороне поставщика услуг.
Access-Control-Allow-Origin
является заголовком только для ответа. Для получения дополнительной информации https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers
Ответ 4
Согласно W3C, если для атрибута состояния установлено значение 0, это означает, что:
- Состояние UNSENT или OPENED.
или
Я думаю, что это не проблема Angular2
, похоже, что ваш запрос имеет проблемы.
Ответ 5
Вам следует использовать сторонний протокол HTTP-протокола (например, CharlesProxy), а не инструменты Chrome dev, чтобы подтвердить, какие заголовки фактически отправляются в службу API, и если он возвращает 401.
Ответ 6
У меня была такая же проблема, и из-за того, что сервер не отправил правильный ответ (даже если в протоколе консоли указано, что ошибка 401 Angular имеет статус 0). Мой сервер был Tomcat с Java-приложением, используя Spring MVC и Spring Security.
Теперь он работает с использованием следующей настройки:
SecurityConfig.java
...
protected void configure(HttpSecurity http) throws Exception {
....
http.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);
// allow CORS option calls
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
...
SomeAuthenticationEntryPoint.java
@Component
public class SomeAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
HttpStatus responseStatus = HttpStatus.UNAUTHORIZED;
response.sendError(responseStatus.value(), responseStatus.getReasonPhrase());
}
}
web.xml
<error-page>
<error-code>403</error-code>
<location>/errors/unauthorised</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/errors/unauthorised</location>
</error-page>
Контроллер для обработки ранее установленных /errors/...
@RestController
@RequestMapping("/errors")
public class SecurityExceptionController {
@RequestMapping("forbidden")
public void resourceNotFound() throws Exception {
// Intentionally empty
}
@RequestMapping("unauthorised")
public void unAuthorised() throws Exception {
// Intentionally empty
}
}
}
Ответ 7
Наткнулся на этот предмет:
В моем случае произошло следующее:
- Я запрашивал REST из другого домена
- Ресурс вернул 401, но в ответе об ошибке не было установлено "Access-Control-Allow-Origin".
- Chrome (или ваш браузер) получил 401 и отобразился на вкладке сети (см. Ниже: 401), но никогда не переходил на Angular
![enter image description here]()
-
поскольку не было разрешено CORS (отсутствует заголовок "Access-Control-Allow-Origin") - Chrome не смог передать этот ответ в Angular. Таким образом, я мог видеть 401 в Chrome, но не в Angular.
-
Решение было простым (распространяется на ответ TimothyBrake) - добавить отсутствующий заголовок в ответ об ошибке. В Spring boot я поставил: response.addHeader("Access-Control-Allow-Origin", "*");
и я разобрался.
@Component
public class JwtUnauthorizedResponseAuthenticationEntryPoint
implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You would need to provide the Jwt Token to Access This resource");
}
}
PS: убедитесь, что компонент указан в конфигурации HttpSecurity в вашем WebSecurityConfigurerAdapter. Обратитесь к: https://www.baeldung.com/spring-security-basic-authentication в случае сомнений.
Надеюсь это поможет.