Ionic 3+Angular 5中通过HTTPClient设置Authorization Header异常问题
Hey,我来帮你搞定这个问题!首先得明确:你的自定义头出现在Access-Control-Request-Headers里,这是浏览器跨域预检请求(OPTIONS)的正常行为,但如果实际请求没正确带上头,或者后端没处理好预检,就会导致请求失败。下面一步步解决:
1. 先确认你的拦截器代码是否正确
先补全你没写完的拦截器代码,确保正确克隆请求并添加头(HttpRequest是不可变对象,必须通过clone修改):
import { Injectable, NgModule } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; @Injectable() export class CustomHeaderInterceptor implements HttpInterceptor { // 拦截请求并添加自定义头 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 克隆请求并注入自定义头 const modifiedRequest = req.clone({ setHeaders: { 'X-App-Version': '1.0.0', // 示例自定义头 'Authorization': `Bearer ${localStorage.getItem('authToken')}` // 比如携带认证token } }); // 传递修改后的请求给下一个拦截器/HttpClient return next.handle(modifiedRequest); } } // 注册拦截器的模块 @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: CustomHeaderInterceptor, multi: true // 必须设为true,允许多个拦截器共存 } ] }) export class InterceptorModule {}
记得在app.module.ts里导入这个InterceptorModule,或者直接把providers配置写在app.module.ts的providers数组中。
2. 理解为什么会出现Access-Control-Request-Headers
当你发送跨域请求(比如Ionic app运行在localhost:8100,API部署在localhost:3000),且请求包含自定义头时,浏览器会先发送一个OPTIONS类型的预检请求,用来询问后端:“我接下来要发送这些头,你允许吗?”
此时Access-Control-Request-Headers字段就是用来告诉后端要携带的自定义头列表,这是浏览器的安全机制,本身不是错误。但如果后端没有正确响应这个预检请求,实际的GET/POST请求就会被浏览器拦截。
3. 后端必须正确处理OPTIONS请求
后端需要配置CORS,明确允许你的自定义头和请求方法。这里以Node.js/Express为例:
方法1:使用cors中间件(推荐)
const express = require('express'); const cors = require('cors'); const app = express(); const corsConfig = { origin: 'http://localhost:8100', // 你的Ionic应用地址 allowedHeaders: ['Content-Type', 'X-App-Version', 'Authorization'], // 明确列出允许的自定义头 methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的请求方法 credentials: true // 如果需要携带cookie/认证信息则开启 }; app.use(cors(corsConfig));
方法2:手动处理OPTIONS请求(不依赖中间件)
app.options('*', (req, res) => { res.header('Access-Control-Allow-Origin', 'http://localhost:8100'); res.header('Access-Control-Allow-Headers', 'Content-Type, X-App-Version, Authorization'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.sendStatus(200); // 响应预检请求 });
注意:如果API部署在公网域名,要把origin改成对应的地址,不建议用*(存在安全风险)。
4. 额外检查点
- 避免拦截器冲突:如果有多个拦截器,执行顺序是按providers数组的顺序来的,后面的拦截器会覆盖前面的头配置,要注意顺序。
- 同域测试验证:如果在同域下请求API,浏览器不会发送预检请求,自定义头会直接带上,你可以用这个场景验证拦截器是否正常工作。
总结一下:Access-Control-Request-Headers只是预检请求的正常字段,只要后端正确响应OPTIONS请求,允许你的自定义头,实际请求就会正常带上这些头,问题就能解决啦!
内容的提问来源于stack exchange,提问作者Sourabh Chopade

