【问题标题】:Angular 9: Unable to change or modify HTTP headersAngular 9:无法更改或修改 HTTP 标头
【发布时间】:2020-07-04 13:09:09
【问题描述】:

我的 API 服务器在 Lumen 框架上运行,并且我在那里安装了一个 CORS 中间件,并附带一个管理 JSON POST 数据的中间件。在服务器端,一切都很完美。

现在,对于 UI,我使用 Angular 9 和 Material 布局。我有一个非常简单的 login 组件:它基本上验证输入,然后调用与我的 API 服务器通信的服务 AuthService

AuthService 非常简单:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse, HttpParams } from '@angular/common/http';

export interface Token {
  token: string;
  token_type: string;
  expires_in: number;
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  public isAuthenticated = new BehaviorSubject<boolean>(false);

  constructor(
    private http: HttpClient,
    private router: Router
  ) {}

  async checkAuthenticated() {
    const authToken = localStorage.getItem('access_token');
    return (authToken !== null);
  }

  getToken() {
    return localStorage.getItem('access_token');
  }

  async login(username: string, password: string) {
    const api = 'http://api.elektron.test/v1/login';
    const headers = new HttpHeaders({'Content-Type': 'application/json; charset=UTF-8'});

    const body = JSON.stringify({
      email: username,
      password
    });

    // tslint:disable-next-line:max-line-length
    return this.http.post(api, body)
      .subscribe((res: any) => {
        if(res.token) {
          this.isAuthenticated.next(true);
          localStorage.setItem('access_token', res.token);
        }
      }, error => {
        console.error(error);
      }, () => {
        console.log('etstamente');
      });
  }

  async logout(redirect: string) {
    const removeToken = localStorage.removeItem('access_token');

    if (removeToken == null) {
      this.isAuthenticated.next(false);
      this.router.navigate([redirect]);
    }
  }

  handleError(error: HttpErrorResponse) {
    let msg = '';
    if (error.error instanceof ErrorEvent) {
      // client-side error
      msg = error.error.message;
    } else {
      // server-side error
      msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    return throwError(msg);
  }
}

this.http.post 中,我可以在第三个参数中传递额外的标头,我已经尝试过了,但是我面临的问题是,无论我传入哪个标头,当我调用该请求时,@987654323 @ 永远不会发送。

我尝试的另一个想法是使用拦截器:

import {HttpInterceptor, HttpRequest, HttpHandler, HttpHeaders} from '@angular/common/http';
import { AuthService } from './auth.service';

@Injectable()

export class AuthInterceptor implements HttpInterceptor {
  constructor(private authService: AuthService) { }

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = this.authService.getToken();

    req = req.clone({
      responseType: 'json'
    });

    if (token) {
      req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + token) });
    }

    if (!req.headers.has('Content-Type')) {
      req = req.clone({
        setHeaders: {
          'Content-Type': 'application/json',
        }
      });
    }

    // setting the accept header
    req = req.clone({ headers: req.headers.set('Accept', 'application/json') });

    return next.handle(req);
  }
}

当它到达那里的任何 req.clone 语句时,我最终的行为与之前对 POST 请求的解释相同。

所以,我不知道我在这里做错了什么或导致这种情况的原因。在 Chrome 浏览器中,当我尝试查看请求标头时,在网络选项卡下的控制台中,当应用上述这些情况时,它会声明 显示临时标头 - 我找到了一些 Stack Overflow 答案在那个问题上,但他们都没有解决我的问题。

我花了 5-6 个小时在网上搜索解决方案,尝试了一些我的想法,但都无济于事。


编辑:此问题与 Angular 无关,而与服务器和后端配置以及处理预检请求有关。

【问题讨论】:

    标签: angular http-headers lumen preflight http-options-method


    【解决方案1】:

    经过一个不眠之夜,我终于解决了这个问题,这不是Angular或我的代码的问题,而是Web服务器的配置问题。

    如果有人遇到类似的情况,这个答案可能会提供一个潜在的解决方案,这是一个preflight request 的书籍示例:

    CORS 预检请求是一个 CORS 请求,用于检查是否 理解 CORS 协议并且服务器知道使用特定的 方法和标头。

    这是一个 OPTIONS 请求,使用三个 HTTP 请求标头: Access-Control-Request-Method、Access-Control-Request-Headers 和 源头。

    这意味着在 Angular 应用程序发出每个请求之前,还有另一个请求会通过 OPTIONS 请求针对服务器检查 CORS 选项。

    我的服务器设置和 Lumen/Laravel CORS 设置一直失败。这就是我的CorsMiddleware 从一开始的样子:

    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    /**
     * Class CorsMiddleware
     * @package App\Http\Middleware
     */
    class CorsMiddleware
    {
        /**
         * Handle an incoming request.
         *
         * @param Request $request
         * @param Closure $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            $headers = [
                'Access-Control-Allow-Credentials' => 'true',
                'Access-Control-Max-Age' => '86400',
                'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, PATCH, HEAD, DELETE',
                'Access-Control-Allow-Headers' => 'X-Requested-With, Content-Type, Accept, Origin, Authorization',
                'Access-Control-Expose-Headers' => 'X-Requested-With, Content-Type, Accept, Origin, Authorization',
                'Access-Control-Allow-Origin' => '*',
            ];
    
            if ($request->isMethod('OPTIONS')) {
                return response()->json(['method' => 'OPTIONS'], 200, $headers);
            }
    
            $response = $next($request);
    
            foreach($headers as $key => $value) {
                $response->header($key, $value);
            }
    
            return $response;
        }
    }
    

    然后这个中间件被正确注入bootstrap/app.php 为:

    $app->routeMiddleware([
        'cors' => App\Http\Middleware\CorsMiddleware::class,
        ...,
    ]);
    

    当这个中间件运行时,所有的标头都在请求响应中发送,但是,CorsMiddleware 中的这条语句从未达到这个条件,即使我尝试使用 Postman:

    if ($request->isMethod('OPTIONS')) {
        return response()->json(['method' => 'OPTIONS'], 200, $headers);
    }
    

    原因是 routes/web.php 没有处理任何 OPTIONS 请求,所以这是由 Web 服务器本身处理的,并且由于我使用 Apache 和 .htaccess,这也导致了一些小问题,但我不想坚持让 Apache 处理这个问题。我想保持一个约定,大部分事情都由 Lumen/Laravel 处理。

    所以,为了让我的 CorsMiddleware 捕获 OPTIONS 请求,我解决了整个问题,将其添加到我的主要 routes/web.php 文件之上:

    Route::options('/{any:.*}', ['middleware' => ['cors']]);
    

    现在CorsMiddleware 中之前提到的OPTIONS 案例从未发生过,如何解决,这解决了我的整个问题。

    【讨论】:

      【解决方案2】:

      这可能是问题所在 req = req.clone({ 响应类型:'json' });

      尝试将请求克隆到一个新的变量中,例如: var newReq = req.clone({ 响应类型:'json' });

      ....其余代码... 然后返回 newReq。

      【讨论】:

        猜你喜欢
        • 2019-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-02
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多