Angular2 REST запрос HTTP код состояния 401 изменяется на 0

Я разрабатываю приложение Angular2. Кажется, когда мой токен доступа истекает, код состояния HTTP 401 изменяется на значение 0 в объекте ответа. Я получаю 401 несанкционированный, но объект ответа на ошибку имеет статус 0. Это мешает мне перехватить ошибку 401 и попытаться обновить токен. Что вызывает изменение кода состояния HTTP 401 в код состояния HTTP 0?

вот скриншот из Firefox консоль:

enter image description here

вот мой код:

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, которая расширяет HTTP Angular2, поэтому я могу перехватывать ошибки в одном месте.

в Google Chrome я получаю это сообщение об ошибке:

XMLHttpRequest не удается загрузить https://api.cloudcms.com/repositories/XXXXXXXXXXXXXXXX/branches/XXXXXXXXXXXXXXXX/nodesXXXXXXXXXXXXXXXX - ... Нет заголовка "Access-Control-Allow-Origin" присутствует на запрашиваемый ресурс. Происхождения 'http://screwtopmedia.local.solutiaconsulting.com', следовательно, не разрешен доступ. Ответ имел код состояния HTTP 401.

это сбивает с толку, потому что я включаю заголовок "Access-Control-Allow-Origin" в запрос.

вот изображение результатов, полученных в Google Chrome:

enter image description here

Я попытался получить доступ к заголовку ответа "WWW-Authenticate" в качестве средства ловушка для 401. Однако следующий код возвращает значение NULL:

err.headers.get("WWW-Authenticate")

это озадачивает, что я получаю проблему CORS, потому что я не получаю никаких ошибок CORS, когда предоставляется действительный токен доступа.

Как мне поймать код состояния HTTP 401? Почему 401 код состояния HTTP изменяется на 0?

Спасибо за вашу помощь.

6 ответов


Я работаю на Cloud CMS. Я могу подтвердить, что мы правильно установили заголовки CORS для вызовов API. Однако для 401 ответа заголовки не устанавливаются должным образом. Это было решено, и исправление будет доступно в общедоступном API в конце этой недели.

кстати, если вы используете наш драйвер javascripthttps://github.com/gitana/gitana-javascript-driver вместо того, чтобы писать в API напрямую, поток повторной аутентификации обрабатывается автоматически, и вам не нужно ловить 401 ошибки вообще.


вопрос CORS запросы см. этот вопрос github

заголовок "Access-Control-Allow-Origin" отсутствует в запрошенном заголовке ресурс

означает, что 'Access-Control-Allow-Origin' требуется в заголовках ответов.

Angular не получает никаких кодов состояния, поэтому он дает вам 0 что вызвано браузером, не позволяющим xml parser для разбора response из-за недопустимого headers.

вам нужно добавить правильное заголовки CORS на error response а также success.


если 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):

лукасп прокомментировал 19 августа 2013

Я нашел проблему на некоторое время, но я забыл опубликовать здесь ответ. Каждый ответ, даже Ошибка 500, должен иметь прикрепленные заголовки CORS. Если сервер не присоединяет заголовки CORS к ответу Error 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 - это только HTTP-заголовок ответа. Для получения дополнительной информации https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers


по данным W3C по, если атрибут status имеет значение 0, это означает, что:

  • состояние не отправлено или открыто.

или

  • установлен флаг ошибки.

Я думаю, что это не Angular2 вопрос, похоже, что ваш запрос имеет проблемы.


вы должны использовать сторонний монитор протокола http (например, CharlesProxy), а не инструменты Chrome dev, чтобы подтвердить, какие заголовки фактически отправляются в службу API, и если он возвращает 401.


у меня была та же проблема и из-за того, что сервер не отправил правильный ответ (хотя в журнале консоли указано 401, угловая ошибка имела статус 0). Мой сервер был Tomcat с Java-приложением, использующим Spring MVC и Spring Security.

теперь он работает с помощью folowing setup:

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>

контроллер для обработки /ошибки./.. ранее определено

@RestController
@RequestMapping("/errors")
public class SecurityExceptionController {

    @RequestMapping("forbidden")
    public void resourceNotFound() throws Exception {
        // Intentionally empty
    }

    @RequestMapping("unauthorised")
    public void unAuthorised() throws Exception {
        // Intentionally empty
        }

    }
}