代码之家  ›  专栏  ›  技术社区  ›  jprice92

为什么添加HTTP拦截器会导致CORS错误?

  •  0
  • jprice92  · 技术社区  · 5 年前

    我正在开发一个带有PHP REST Api的Angular 6应用程序。我的开发环境托管在本地主机上,因此首先我必须启用访问控制Allow Origin:*以绕过我遇到的任何CORS错误。

    最近,我一直在尝试使用拦截器实现JWT,以便将它们添加到我的HTTP请求中。当我启用了以下谷歌示例中的解释器后,我又开始出现CORS错误:

    blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header
    

    我肯定这和我的拦截器有关,因为当我把它注释掉时,它又能工作了。下面是我想要使用的拦截器的代码:

    import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from 
    '@angular/common/http';
    import { Injectable } from '@angular/core';
    import { Observable } from 'rxjs/index';
    import {AuthService} from './auth.service';
    
    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
      constructor(public auth: AuthService) {}
    
      intercept(req: HttpRequest<any>, next: HttpHandler): 
    Observable<HttpEvent<any>> {
        req = req.clone({
          setHeaders: {
             'Content-Type' : 'application/json; charset=utf-8',
            // 'Accept'       : 'application/json',
            'Authorization': `Bearer ${this.auth.getToken()}`
          }
        });
    
        return next.handle(req);
      }
    }
    

    我甚至尝试将其剥离,以便将授权头设置为可用。

    此时,我只想看到$\u服务器变量中的授权头,因此PHP的测试非常简单:

    <?php
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, 
    OPTIONS');
    header('Access-Control-Allow-Headers: Authorization, Access, Origin, 
    Content-Type, X-Auth-Token');
    
    echo json_encode(array(
            'status' => 0
            ,'message'=> $_SERVER
        ));
    
    exit;
    

    以下是我的应用程序模块,显示拦截器已配置:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { LoginFormComponent } from './login-form/login-form.component';
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    
    import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
    import {AuthInterceptor} from './auth.interceptor';
    import { MessagesComponent } from './messages/messages.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        LoginFormComponent,
        MessagesComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        HttpClientModule,
        FormsModule,
        ReactiveFormsModule
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AuthInterceptor,
          multi: true
        }
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    下面是我用来发送HTTP请求的登录服务:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { ServerResponse } from './server-response';
    import {MessagesService} from './messages.service';
    import {AuthService} from './auth.service';
    
    @Injectable({
      providedIn: 'root'
    })
    
    export class LoginService {
    
      constructor(private http: HttpClient,
                  private ms: MessagesService,
                  private auth: AuthService) { }
      login(formData) {
        this.ms.clear();
        console.log('JSON data', JSON.stringify((formData)));
        console.log(this.auth.getToken());
        return this.http.post('http://jpapp.com/api/login/login.php',     JSON.stringify(formData))
          .subscribe((rs: ServerResponse) => {
            console.log('%cPost Success', 'color: green;');
            console.log(rs);
        }, (error) => ({status: -99, message: error}));
      }
    }
    

    如果我删除了拦截器,Requet头如下所示(这就是我尝试将内容类型更改为纯文本的原因):

    Provisional headers are shown
    Accept: application/json, text/plain, */*
    Content-Type: text/plain
    Origin: http://localhost:4200
    Referer: http://localhost:4200/
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 
    (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
    

    当我启用拦截器时,请求头如下所示:

    Provisional headers are shown
    Access-Control-Request-Headers: authorization,content-type
    Access-Control-Request-Method: POST
    Origin: http://localhost:4200
    Referer: http://localhost:4200/
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 
    (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
    

    我已经读到,我可能可以通过chrome扩展绕过这一点,但我想在安装扩展之前先知道我的代码中是否有什么内容。

    欢迎提供任何信息!

    1 回复  |  直到 5 年前
        1
  •  3
  •   Community Romance    4 年前

    使现代化

    复杂的 易于理解的 cors请求。在我的情况下,只要添加自定义标头,或者执行任何使其不再是简单请求的操作,默认情况下,它就会使用OPTIONS方法而不是POST方法发送飞行前请求。本文非常好地解释了cors和一个简单与复杂的请求: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

    飞行前响应错误与代码本身无关。问题在于我的IIS 10 web服务器的配置。

    在本条之后: CORS Module Configuration Reference 我将所需的cors节点添加到web.config文件中,现在它可以正常工作了

    我可以通过安装Allow控件Allow Origin:*Chrome扩展绕过飞行前请求CORS错误 https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en

    *://*/* 如果我将其更改为匹配我的URL,我会再次收到CORS错误,但这可能只是我的模式匹配问题。如果能解释一下它是如何工作的,那就太好了。

    我仍然在寻找一个原因,为什么通过拦截器传递授权会破坏服务器访问控制允许源:*因为我相信,一旦我实际部署此应用程序和api,我会再次遇到这个问题。将此扩展与默认配置一起使用也是一个PITA,因为它将破坏一堆站点。

        2
  •  0
  •   Lalo19    4 年前

    我在登录中获取令牌时遇到了同样的问题,我通过在拦截器请求中添加if-else解决了这个问题

       const yourToken = this.auth.getToken();
    
        if (yourToken) {
            req = req.clone({
                setHeaders: {
                    'Content-Type': 'application/json; charset=utf-8',
                    Accept: 'application/json',
                    Authorization: `Bearer ${yourToken}`
                }
            });
        } else {
            req = req.clone({
                setHeaders: {
                    'Content-Type': 'application/json; charset=utf-8',
                    Accept: 'application/json'
                }
            });
        }
    
        return next.handle(req);
    
        3
  •  0
  •   cozmik05    3 年前

    if (!(req.headers.get('No-auth')) || ((req.headers.get('No-auth') === 'True') && (req.headers.get('TokenRefresh') === 'False')))enter code here { return next.handle(req.clone());} 如果请求中没有自定义头,则表示没有提供头,这样做只是克隆原始请求。