簡體   English   中英

為什么添加 HTTP Interceptor 會導致 CORS 錯誤?

[英]Why does adding an HTTP Interceptor cause CORS errors?

我正在開發一個帶有 PHP REST Api 的 Angular 6 應用程序。 我的開發環境托管在我的本地主機上,所以一開始我必須啟用 Access-Control-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);
  }
}

我什至試圖將其剝離以僅設置 Authorization 標頭以使用。

如果我注釋掉 Authorization 標頭並只保留 Content-Type,我仍然會收到 CORS 錯誤。 如果我將 Content-type 更改為純文本/文本,它可以工作,但是我沒有授權標頭。 如果我將內容類型保留為純文本/文本並添加授權標頭,則會出現 CORS 錯誤。

在這一點上,我只想查看 $_SERVER 變量中的授權標頭,因此 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 擴展程序繞過它,但想知道在安裝擴展程序之前,我的代碼中是否有某些內容進行嘗試。

任何信息表示贊賞!

更新

編輯:我應該提到將 req.clone() 設置為我發現的空白作品的原因是因為預檢只發生在復雜而不是簡單的cors 請求上。 一旦您添加自定義標頭,在我的情況下授權或執行任何導致它不再是簡單請求的事情,默認情況下,它會使用 OPTIONS 方法而不是在我的情況下發送預檢請求。 這篇文章很好地解釋了 cors 和一個簡單與復雜的請求: https : //developer.mozilla.org/en-US/docs/Web/HTTP/CORS

預檢響應錯誤與代碼本身無關。 問題出在我的 IIS 10 Web 服務器的配置上。

遵循這篇文章: CORS 模塊配置參考我將所需的 cors 節點添加到我的 web.config 文件中,現在它可以正常工作

我能夠通過安裝 Allow-Control-Allow-Origin 繞過預檢請求 CORS 錯誤: * Chrome 擴展 https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=恩

如果我保持默認 URL 匹配 *://*/*似乎仍然有效,如果我將其更改為匹配我的 URL,我再次收到 CORS 錯誤,但這可能只是我的模式匹配的問題。 如果能解釋它是如何工作的,那就太好了。

我仍在尋找一個原因,為什么通過攔截器傳遞授權會破壞服務器 Access-Control-Allow-Origin: * 因為我確信一旦我實際部署了這個應用程序和 api,我會再次遇到這個問題。 將此擴展與默認配置一起使用也是一個 PITA,因為它會破壞一堆站點。

我在登錄中獲取令牌時遇到了同樣的問題,我通過在攔截器請求中添加一個 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);

我還通過檢查請求中是否存在我的自定義標頭來解決此問題,每當我向 get 請求添加標頭時我都會注意到錯誤,並且在沒有標頭的情況下工作正常。 所以我做了這個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());}如果請求中沒有自定義標頭,則表示未提供標頭,這樣做,它只是克隆原始請求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM