【问题标题】:Angular 4: unable to read headers from response - not a CORS issueAngular 4:无法从响应中读取标头 - 不是 CORS 问题
【发布时间】:2018-04-19 17:45:21
【问题描述】:

在服务器自动更新令牌的上下文中,我正在努力解决基础问题:从响应中获取标头数据。

这似乎与 CORS 无关,因为我的 Node/express allwos Authorization/x-access-token 并相应地响应(请参阅下面的网络选项卡屏幕截图)。

我希望看到的第一步是从响应中读取标题。请参阅我的代码,它是文档中的样板文件。获取“Content-Length”的事件返回 null。

auth-service.ts

login(username:string, password:string):Observable<boolean>{
    this.loggedIn = false;
    return new Observable( (observer:Observer<boolean>) => {

      const body = {user: username, pwd: password};
      const url = this.config.API_ENDPOINT_PUBLIC_AUTH;

      this.httpClient.post(url, body, {
        responseType: 'text',
        observe: "response"
      }).first().subscribe(
        (response:HttpResponse<string>) => {

          // DEBUG
          console.log(response.headers.get('Authorization'));
          console.log(response.headers.get('X-Test-Header'));
          console.log(response.headers.get('Content-length'));


          this.token = response.headers.get('Authorization');
          this.storeToken(this.token);
          this.currentUser = username;
          this.loggedIn = true;
          this.authChanged$.next('auth');
          observer.next(true);
        },
        (err) => observer.next(false),
        () => {},
      );
    });
  }

控制台输出:

将此请求与我的网络选项卡的内容进行比较:

不用说我的 HttpInterceptor 也不起作用 - 在响应中提供“授权”标头后,它使用该值作为新令牌。这是为了实现令牌的自动更新:

token.interceptor.ts

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    const authService = this.injector.get(AuthService);
    const token = authService.getToken();

    if(token){
      request = request.clone({
        setHeaders: { 'x-access-token' : token }
      });
    }
    
    return next.handle(request).do(
      (event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          const response:HttpResponse<any> = (<HttpResponse<any>> event);
          const authorizationHeader = response.headers.get('Authorization');
          console.log('Authorization header value: ' + authorizationHeader);
          if(authorizationHeader){
            authService.setToken(authorizationHeader);
          }
        }
      },
      (err: any) => {
      if (err instanceof HttpErrorResponse){
        if (err.status === 401) {
          this.router.navigate(['/']);
        }
      }
    });
  }

【问题讨论】:

  • 会不会和内容类型有关?我看到您在 TS 代码中将响应类型设置为“文本”,但是响应本身是“应用程序/json”。如果我错了,请告诉我!
  • 确实很有趣,我没有注意到...我必须将预期类型设置为“字符串”,因为 API 返回一个空正文,只有一个状态 200 和一个包含令牌的标头。如果效果更好,让我尝试 rreturn 一个空的 json。
  • 不,没有帮助。无法从响应中读取除“Content-Type”以外的任何标头。
  • 我明白了……我再看看
  • 好的,刚刚找到原因了。使用答案从格式化功能中受益。感谢您的时间@avilac!

标签: angular angular-http-interceptors angular-httpclient


【解决方案1】:

好的,这就是答案:我使用 Node.js/Express 作为后端,即使在 Chrome 的网络选项卡中可以看到标头,它也不能让 Angular 处理它们。

“为什么它们是可见的却不能使用?”我还不清楚。

配置您的 Node/Express 应用程序(在此处查找评论“解决方案”):

function configureExpress(expressApp){  
    expressApp.use(bodyparser.urlencoded({ extended: true }));
    expressApp.use(bodyparser.json());

    // Middleware: Use CORS, add headers and allow methods
    expressApp.use(expressMiddleware);
}

function expressMiddleware(req, res, next) {

    // Request origin: Allow ALL
    res.header("Access-Control-Allow-Origin", "*");

    // Allowed headers
    res.header("Access-Control-Allow-Headers",

        "Origin"
        +",X-Requested-With"   // Dont allow AJAX CORS without server consent - see http://stackoverflow.com/questions/17478731/whats-the-point-of-the-x-requested-with-header
        +",x-access-token"
        +",Content-Type"
        +",Authorization"
        +",Accept"
    );

    // SOLUTION HERE
    // Allow headers access
    res.header("access-control-expose-headers",
        ",Authorization"
        +",Content-Length"
        );

    // Allowed methods
    res.header('Access-Control-Allow-Methods',
        'GET,'
        +',POST'
        +',OPTIONS'
        +',PUT,'
        +',DELETE'
    );

    // Handle CORS requests: cross-domain/origin requests will begin with an OPTION request to the same endpoint.
    if('OPTIONS' === req.method){
        res.sendStatus(200);
    }

    else{
        // Request validations complete
        next();
    }
}

【讨论】:

    【解决方案2】:

    添加更多相关信息的答案

    我正在使用 Angular 7,只是在 API 的 Access-Control-Expose-Headers 中添加自定义标头对我不起作用。

    这里要注意的是,自定义标头必须以小写形式作为 Access-Control-Expose-Headers

    中的逗号分隔值

    示例(快速)

    const cors = require('cors');
    
    const corsOptions = {
        allowedHeaders: 'x-custom-one,x-custom-two',
        exposedHeaders: 'x-custom-one,x-custom-two'
    }
    app.use(cors(corsOptions));
    

    【讨论】:

      猜你喜欢
      • 2017-03-21
      • 2018-08-31
      • 2017-04-02
      • 1970-01-01
      • 2015-10-09
      • 1970-01-01
      • 1970-01-01
      • 2018-06-19
      • 1970-01-01
      相关资源
      最近更新 更多