Подтвердить что ты не робот

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?

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

4b9b3361

Ответ 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 в случае сомнений.

Надеюсь это поможет.