簡體   English   中英

API Gateway CORS:沒有“Access-Control-Allow-Origin”標頭

[英]API Gateway CORS: no 'Access-Control-Allow-Origin' header

雖然已經通過 API Gateway 設置了 CORS 並設置了Access-Control-Allow-Origin標頭,但在 Chrome 中嘗試從 AJAX 調用 API 時仍然收到以下錯誤:

XMLHttpRequest 無法加載http://XXXXX.execute-api.us-west-2.amazonaws.com/beta/YYYYY 請求的資源上不存在“Access-Control-Allow-Origin”標頭。 因此,Origin 'null' 不允許訪問。 響應具有 HTTP 狀態代碼 403。

我試圖通過Postman獲取 URL,它顯示上述標頭已成功傳遞:

傳遞的標頭

從 OPTIONS 響應中:

響應標頭

如何從瀏覽器調用我的 API 而不恢復為 JSON-P?

我遇到同樣的問題。 我已經用了 10 小時來找出答案。

https://serverless.com/framework/docs/providers/aws/events/apigateway/

// handler.js

'use strict';

module.exports.hello = function(event, context, callback) {

const response = {
  statusCode: 200,
  headers: {
    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS 
  },
  body: JSON.stringify({ "message": "Hello World!" })
};

callback(null, response);
};

如果其他人仍然遇到這種情況 - 我能夠在我的應用程序中找到根本原因。

如果您使用自定義授權器運行 API-Gateway - API-Gateway 將在實際訪問您的服務器之前發送 401 或 403。 默認情況下 - 從自定義授權方返回 4xx 時,未為 CORS 配置 API 網關。

另外 - 如果您碰巧從通過 API Gateway 運行的請求中獲得01的狀態代碼,這可能是您的問題。

要修復 - 在 API 網關配置中 - 轉到“網關響應”,展開“默認 4XX”並在那里添加 CORS 配置標頭。 IE

Access-Control-Allow-Origin: '*'

確保重新部署您的網關- 瞧!

如果您已經嘗試了有關此問題的所有方法,但都無濟於事,那么您最終會得到我所做的。 事實證明,亞馬遜現有的 CORS 設置指導工作得很好……只要確保你記得重新部署 CORS 編輯向導,即使有所有漂亮的小綠色復選標記,也不會對您的 API 進行實時更新。 也許很明顯,但它難倒了我半天。

在此處輸入圖片說明

1)我需要做與@riseres 和其他一些更改相同的事情。這是我的響應標頭:

headers: {
            'Access-Control-Allow-Origin' : '*',
            'Access-Control-Allow-Headers':'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
            'Access-Control-Allow-Credentials' : true,
            'Content-Type': 'application/json'
        }

2和

根據此文檔:

http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

當您在 API Gateway 配置上為 lambda 函數使用代理時,post 或 get 方法沒有添加標頭,只有選項添加。 您必須在響應(服務器或 lambda 響應)中手動執行此操作。

3) 和

除此之外,我需要在我的 API 網關 post 方法中禁用“API Key Required”選項。

讓我的示例工作:我剛剛在生成的 nodejs Lambda 函數中插入了'Access-Control-Allow-Origin': '*', inside headers:{} 沒有對 Lambda 生成的 API 層進行任何更改。

這是我的 NodeJS:

'use strict';
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();
exports.handler = ( event, context, callback ) => {
    const done = ( err, res ) => callback( null, {
        statusCode: err ? '400' : '200',
        body: err ? err.message : JSON.stringify(res),
        headers:{ 'Access-Control-Allow-Origin' : '*' },
    });
    switch( event.httpMethod ) {
        ...
    }
};

這是我的 AJAX 調用

$.ajax({
    url: 'https://x.execute-api.x-x-x.amazonaws.com/prod/fnXx?TableName=x',
    type: 'GET',
    beforeSend: function(){ $( '#loader' ).show();},
    success: function( res ) { alert( JSON.stringify(res) ); },
    error:function(e){ alert('Lambda returned error\n\n' + e.responseText); },
    complete:function(){ $('#loader').hide(); }
});

我剛剛在我的 lambda 函數響應中添加了標頭,它就像一個魅力

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hey it works'),
        headers:{ 'Access-Control-Allow-Origin' : '*' }
    };
    return response;
};

對於 Google 員工:

原因如下:

  • 簡單的請求,或者,沒有 cookie 的GET / POST不會觸發預檢
  • 為路徑配置 CORS 時,API Gateway 只會為該路徑創建OPTIONS方法,然后在用戶調用OPTIONS時使用模擬響應發送Allow-Origin標頭,但GET / POST不會自動獲取Allow-Origin
  • 如果您嘗試在開啟 CORS 模式的情況下發送簡單請求,您將收到錯誤消息,因為該響應沒有Allow-Origin標頭
  • 您可以遵循最佳實踐,簡單的請求並不意味着向用戶發送響應,將身份驗證/cookie 與您的請求一起發送以使其“不簡單”並且預檢將觸發
  • 盡管如此,您仍必須為以下OPTIONS的請求自行發送 CORS 標頭

把它們加起來:

  • API Gateway 只會自動生成無害的OPTIONS
  • OPTIONS僅被瀏覽器用作檢查路徑上 CORS可能性的預防措施
  • 是否接受CORS 取決於實際方法,例如GET / POST
  • 您必須在響應中手動發送適當的標頭

對我來說,最終有效的答案是 James Shapiro 的評論來自 Alex R 的答案(第二高投票)。 我首先遇到了這個 API 網關問題,嘗試獲取托管在 S3 中的靜態網頁以使用 lambda 處理聯系我們頁面並發送電子郵件。 只需檢查 [ ] Default 4XX 即可修復錯誤消息。

在此處輸入圖片說明

我在里面找到了一個簡單的解決方案

API 網關 > 選擇您的 API 端點 > 選擇方法(在我的情況下是 POST)

現在有一個下拉操作 > 啟用 CORS .. 選擇它。

現在再次選擇下拉 ACTIONS > Deploy API(重新部署它)

在此處輸入圖片說明

有效 !

在我意識到 lambda 授權器失敗並且由於某種未知原因被轉換為 CORS 錯誤后,我開始工作。 對我的授權人的簡單修復(以及我應該首先添加的一些授權人測試)並且它起作用了。 對我來說,API 網關操作“啟用 CORS”是必需的。 這在我的 API 中添加了我需要的所有標頭和其他設置。

更改您的功能或代碼后 請按照以下兩個步驟操作。

首先啟用 CORS,然后每次都部署 API

在為POSTOPTIONS啟用 CORS 后部署代碼對我有用。

我正在運行aws-serverless-express ,在我的情況下需要編輯simple-proxy-api.yaml

在將 CORS 配置為https://example.com之前,我只是交換了我的站點名稱並通過npm run setup重新部署,它更新了我現有的 lambda/stack。

#...
/:
#...
method.response.header.Access-Control-Allow-Origin: "'https://example.com'"
#...
/{proxy+}:
method.response.header.Access-Control-Allow-Origin: "'https://example.com'"
#...

就我而言,由於我使用 AWS_IAM 作為 API 網關的授權方法,我需要授予我的 IAM 角色訪問端點的權限。

對我來說,因為我使用的是非常標准的 React fetch 調用,所以這可以使用上面的一些 AWS 控制台和 Lambda 修復來修復,但是我的 Lambda 返回了正確的標頭(我也使用了代理模式),我需要打包我的應用程序升級到 SAM 模板,所以我不能花時間在控制台上單擊。

我注意到所有 CORS 的東西都運行良好,直到我將 Cognito Auth 放到我的應用程序中。 我只是在使用越來越多的配置進行 SAM 包/SAM 部署時速度非常慢,直到它壞了,只要我將 Auth 添加到我的 API 網關,它就壞了。 我花了一整天的時間點擊像這樣的精彩討論,尋找一個簡單的解決方法,但最終不得不實際閱讀 CORS 正在做什么。 我將為您節省閱讀時間,並為您提供另一個簡單的解決方案(至少對我而言)。

以下是最終有效的 API 網關模板示例 (YAML):

Resources:
  MySearchApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: 'Dev'
      Cors:
        AllowMethods: "'OPTIONS, GET'"
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
        AllowOrigin: "'*'"
      Auth:
        DefaultAuthorizer: MyCognitoSearchAuth
        Authorizers:
          MyCognitoSearchAuth:
            UserPoolArn: "<my hardcoded user pool ARN>"
            AuthType: "COGNITO_USER_POOLS"
        AddDefaultAuthorizerToCorsPreflight: False

注意底部的 AddDefaultAuthorizerToCorsPreflight。 根據我的閱讀,如果您的模板中沒有它,則默認為 True。 並且,當為 True 時,它​​會阻止正常的 OPTIONS 行為來宣布資源在允許的來源方面支持什么。 一旦我明確添加它並將其設置為 False,我的所有問題都解決了。

這意味着如果您遇到此問題並想要更完整地診斷它,您應該訪問 API Gateway 中的資源並檢查您的 OPTIONS 方法是否包含某種形式的身份驗證。 您的 GET 或 POST 需要身份驗證,但如果您的 OPTIONS 啟用了身份驗證,那么您可能會發現自己處於這種情況。 如果您在 AWS 控制台周圍單擊,請嘗試從 OPTIONS 中刪除,重新部署,然后進行測試。 如果您使用的是 SAM CLI,請嘗試我上面的修復。

確保您調用的是正確的路徑。

無論出於何種原因,命中不存在的路徑都可能導致 CORS 相關錯誤。 可能是因為404在其響應中不包含 CORS 標頭。

感謝@jackko 對最初問題的評論。 這是我的問題。 聽起來很傻,但可能發生在任何人身上。

對於Python ,正如@riseres 所提到的,在導入 json 等之后......

// lambda handler

def hello(event, context, callback):
response = {
  statusCode: 200,
  headers: {
    "Access-Control-Allow-Origin" : "*", # Required for CORS support, to work, also you should instead specify the proper origin if credentials are mandatory
    "Access-Control-Allow-Credentials" : True # Required for cookies, authorization headers with HTTPS 
  },
  body: json.dumps({ "message": "Hello World!" })
}

callback(null, response);
}

此問題的另一個根本原因可能是 HTTP/1.1 和 HTTP/2 之間的差異。

症狀:部分用戶(並非全部)在使用我們的軟件時報告出現 CORS 錯誤。

問題:有時缺少Access-Control-Allow-Origin標頭。

上下文:我們有一個 Lambda,專門用於處理OPTIONS請求並使用相應的 CORS 標頭進行回復,例如Access-Control-Allow-Origin匹配列入白名單的Origin

解決方案: API 網關似乎將 HTTP/2 調用的所有標頭轉換為小寫,但保持 HTTP/1.1 的大寫。 這導致對event.headers.origin的訪問失敗。

檢查您是否也遇到此問題:

假設您的 API 位於https://api.example.com ,而您的前端位於https://www.example.com 使用 CURL,使用 HTTP/2 發出請求:

curl -v -X OPTIONS -H 'Origin: https://www.example.com' https://api.example.com

響應輸出應包括標題:

< Access-Control-Allow-Origin: https://www.example.com

使用 HTTP/1.1(或使用小寫的Origin標頭)重復相同的步驟:

curl -v -X OPTIONS --http1.1 -H 'Origin: https://www.example.com' https://api.example.com

如果缺少Access-Control-Allow-Origin標頭,您可能需要在讀取Origin標頭時檢查區分大小寫。

除了其他評論之外,還需要注意的是從您的底層集成返回的狀態,以及是否為該狀態返回了 Access-Control-Allow-Origin 標頭。

執行“啟用 CORS”操作只會設置 200 個狀態。 如果您在端點上有其他人,例如 4xx 和 5xx,您需要自己添加標頭。

就我而言,我啟用了所有方法和網關響應。 然后它就像一個魅力。 不要忘記部署。

在此處輸入圖片說明

對於在 API Gateway 中使用 Cognito 授權器的用戶,實際上無需設置自定義網關響應。 API 網關會阻止預檢,因為它們在默認的 AWS 邏輯中是“未經授權的”。

幸運的是,有一個內置參數可以解決這個問題。 只需將AddDefaultAuthorizerToCorsPreflight: False添加到您的 API Authorizer,API Gateway 將禁用預檢請求的身份驗證。 這是文檔和示例設置:

MyApi:
Type: AWS::Serverless::Api
Properties:
  StageName: Prod
  Cors: 
    AllowHeaders: "'*'"
    AllowMethods: "'*'"
    AllowOrigin: "'*'"
  Auth:
    DefaultAuthorizer: MyCognitoAuthorizer
    AddDefaultAuthorizerToCorsPreflight: False
    Authorizers:
      MyCognitoAuthorizer:
        UserPoolArn: !GetAtt MyCognitoUserPool.Arn

對於未來的患者:

這個該死的問題再次困擾着我,這次是因為我發送了一個自定義標題:

let headers = {
  'Content-Type': 'application/json',
  'Is-Web': true,
  Authorization: `Bearer ${accessToken}`,
};

這個“Is-Web”自定義標頭使 API Gateway 阻止了我的請求並將其屏蔽為 CORS 錯誤。 如果您要發送一個,只需將其刪除並測試即可。 幾乎因此失去了一整天的工作。

我已經有這個問題很長一段時間了。 我最終把它放到我的 python lambda 函數中

 response ={
        'statusCode': statusCode,
        'headers':{
             'Access-Control-Allow-Headers': 'Content-Type',
             'Access-Control-Allow-Origin': '*',
             'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
                  },
                  'body':json.dumps(body)
              }
    return response 

我希望這可以幫助那里的人

就我而言,我只是將獲取請求 URL 寫錯了。 serverless.yml ,你設置corstrue

register-downloadable-client:
    handler: fetch-downloadable-client-data/register.register
    events:
      - http:
          path: register-downloadable-client
          method: post
          integration: lambda
          cors: true
          stage: ${self:custom.stage}

然后在 lambda 處理程序上發送標頭,但是如果在前端使提取請求出錯,則不會在響應中獲得該標頭,並且會收到此錯誤。 因此,請仔細檢查前面的請求 URL。

在 Python 中,您可以按照以下代碼進行操作:

{ "statusCode" : 200,
'headers': 
    {'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': "*"
     },
"body": json.dumps(
    {
    "temperature" : tempArray,
    "time": timeArray
    })
 }

暫無
暫無

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

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