Angular2 REST请求HTTP状态代码401更改为0

时间:2016-08-17 14:17:43

标签: rest angular cors

我正在开发一个Angular2应用程序。似乎当我的访问令牌到期时,401 HTTP状态代码在Response对象中变为值0。我收到401 Unauthorized但ERROR Response对象的状态为0.这阻止我捕获401错误并尝试刷新令牌。是什么导致401 HTTP状态代码被更改为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...');
        });
}

此代码驻留在扩展Angular2的HTTP的自定义http服务中,因此我可以在一个位置拦截错误。

在谷歌浏览器中,我收到以下错误消息:

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错误。

如何捕获401 HTTP状态代码?为什么401 HTTP状态代码被更改为0?

感谢您的帮助。

7 个答案:

答案 0 :(得分:19)

此问题与 CORS请求有关,请参阅this github issue

  

否&#39;访问控制 - 允许 - 来源&#39;标题出现在请求的上   资源

表示响应标头中需要'Access-Control-Allow-Origin'

Angular没有获取任何状态代码,这就是为什么它会导致0导致浏览器不允许xml parser因无效而解析response而导致headers的原因error response

您需要在success以及def newtons_sqrt(initial_guess, x, threshold=0.0001): guess = initial_guess new_guess = (guess+float(x)/guess)/2 while abs(guess-new_guess) > threshold : guess=new_guess new_guess = (guess+float(x)/guess)/2 return new_guess def power(base, exp,threshold=0.00001): if(exp >= 1): # first go fast! temp = power(base, exp / 2); return temp * temp else: # now deal with the fractional part low = 0 high = 1.0 sqr = newtons_sqrt(base/2,base) acc = sqr mid = high / 2 while(abs(mid - exp) > threshold): sqr = newtons_sqrt(sqr/2.0,sqr) if (mid <= exp): low = mid acc *= sqr else: high = mid acc *= (1/sqr) mid = (low + high) / 2; return acc print newtons_sqrt(1,8) print 8**0.5 print power(5,0.76) print 5**0.76 附加正确的 CORS标题

答案 1 :(得分:6)

如果cloudcms.com没有在401响应中设置about-section,那么你无能为力。您必须与他们一起打开支持票,以确认这是否是正常行为。

浏览器中的javascript(FF,Chrome&amp; Safari)我测试过,如果发生CORS错误,则收到任何信息,而不是状态0. Angular2无法控制它。

我创建了一个简单的测试并获得与您相同的结果:

Access-Control-Allow-Origin

经过大量谷歌搜索后,我发现了以下内容(https://github.com/angular/angular.js/issues/3336):

  

lucassp于2013年8月19日发表评论

     

我现在找到了一段时间的问题,但我忘了在这里发帖回复。每个响应,即使是错误500,也必须附加CORS标头。如果服务器没有将CORS标头附加到Error 500响应,那么XHR对象不会解析它,因此XHR对象不会有任何响应主体,状态或任何其他响应数据内部。

Firefox网络监视器的结果似乎支持上述原因。

Javascript请求将收到空响应。 javascript request

普通网址请求(复制并粘贴地址栏中的链接)将获得响应正文 Plain url request

Javascript使用XHRHttpRequest进行http通信。

当XHR回复到达时,浏览器将处理标题,这就是您将看到这些401网络消息的原因。但是,如果XHR回复来自不同的主机,则javascript和响应头不包含CORS头(例如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); } ); } ),浏览器将不会将任何信息传递回XHR层。因此,回复正文将完全为空,没有状态(0)。

我使用FF 48.0.1,Chrome 52.0.2743.116和Safari 9.1.2进行了测试,它们都具有相同的行为。

使用浏览器网络监视器检查这些Access-Control-Allow-Origin: *条目的响应标头,很可能没有401 Unauthorized标头并导致您遇到的问题。这可能是错误或服务提供商方面的设计。

Access-Control-Allow-Origin仅响应http标头。有关https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers

的更多信息

答案 2 :(得分:5)

我为Cloud CMS工作。我可以确认我们在API调用上正确设置了CORS头。但是,对于401响应,标头未正确设置。这已经解决,本周末将在公共API上提供修复。

BTW如果您使用我们的javascript驱动程序https://github.com/gitana/gitana-javascript-driver而不是直接写入API,则会自动处理重新验证流程,您根本不需要捕获401错误。

答案 3 :(得分:2)

根据W3C,如果status属性设置为0,则表示:

  • 州是UNSENT或OPENED。

  • 设置了错误标志。

我认为这不是Angular2问题,您的请求似乎有问题。

答案 4 :(得分:2)

您应该使用第三方http协议监视器(如CharlesProxy)而不是Chrome开发工具来确认哪些标头实际发送到API服务以及是否返回401。

答案 5 :(得分:1)

我遇到了同样的问题,原因是服务器没有发送正确的响应(即使控制台日志声明401,Angular错误的状态为0)。我的服务器是使用Spring MVC和Spring Security的带有Java应用程序的Tomcat。

现在正在使用以下设置:

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
        }

    }
}

答案 6 :(得分:0)

偶然发现此项目:

我的情况是:

  • 我正在从其他域请求REST
  • 资源返回401,但错误响应中未设置“ Access-Control-Allow-Origin”。
  • Chrome(或您的浏览器)收到401并显示在“网络”标签中(请参见以下计数:401),但从未传递给Angular

enter image description here

  • ,因为没有允许的CORS(缺少“ Access-Control-Allow-Origin”标头)-Chrome无法将此响应传递到Angular。这样,我可以在Chrome中看到401,但在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:确保在WebSecurityConfigurerAdapter的HttpSecurity配置中提供了bean。如有疑问,请参见:https://www.baeldung.com/spring-security-basic-authentication

希望这会有所帮助。