Angular 9:无法更改或修改 HTTP 标头
Posted
技术标签:
【中文标题】Angular 9:无法更改或修改 HTTP 标头【英文标题】:Angular 9: Unable to change or modify HTTP headers 【发布时间】: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 无关,而与服务器和后端配置以及处理预检请求有关。
【问题讨论】:
【参考方案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。
【讨论】:
以上是关于Angular 9:无法更改或修改 HTTP 标头的主要内容,如果未能解决你的问题,请参考以下文章
我无法在 Angular 4 上向 laravel api 发送带有标头的 http 请求
Angular 无法从 HttpEvent 标头获取 ETag 标头