如何在无服务器中允许 CORS 用于自定义标头?
Posted
技术标签:
【中文标题】如何在无服务器中允许 CORS 用于自定义标头?【英文标题】:How to allow CORS for custom headers in Serverless? 【发布时间】:2018-06-08 17:06:42 【问题描述】:这里的核心问题是:“如何在使用无服务器框架处理的 CORS GET 请求中允许自定义标头?”。如果您知道答案,请通过 Go,收集 200 美元并请回答该问题。如果这不是一个直接回答的问题,这里是详细信息:
我正在使用 AWS Lambda 上的无服务器框架编写一个应用程序(API 是通过 AWS API Gateway 管理的。坦率地说,我不完全确定这意味着什么或给我带来了什么好处,但这就是无服务器自动为我配置的)。我正在尝试创建一个需要启用 CORS 的开放 API。我正在使用 Lambda 代理集成。我遵循了here 的做法。他们给我带来了部分成功。如果我不包含自定义标头,我的应用程序当前启用了 CORS。但是,它仍然不适用于自定义标题。
当我向我的 API 发送以下请求时:
var data = null;
var xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.addEventListener("readystatechange", function ()
if (this.readyState === 4)
console.log(this.responseText);
);
xhr.open("GET", "https://api.spongebobify.com/");
xhr.setRequestHeader("text", "hey");
xhr.send(data);
...我收到此错误:
Failed to load https://api.spongebobify.com/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://forum.serverless.com' is therefore not allowed access.
如果我使用 Chrome 开发工具检查“响应标头”,则确认此错误消息:响应标头中没有 Access-Control-Allow-Origin。
但是,如果我发送相同的请求并注释掉 setRequestHeader()
,它会完美运行(是的,我知道它返回 403 错误:这是故意行为)。
这就是我认为正在发生的事情。我的服务有两个潜在的 CORS 问题:域相关(不是来自原始域的请求)和自定义标头相关(CORS 规范未安全列出的标头,更多 here)。不知何故,Serverless 框架遇到了第二个问题,这导致它甚至无法发布适当的标头以允许所有 ("*") 域。
这是我的 serverless.yml 配置文件:
# serverless.yml
service: spongebobify
provider:
name: aws
runtime: nodejs6.10
stage: dev
region: us-east-1
functions:
app:
handler: handler.endpoint
events:
- http: GET /
cors:
origin: '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- Startlower
- Text
- Access-Control-Allow-Headers
- Access-Control-Allow-Origin
allowCredentials: false
这是我要运行的函数。您可以看到我 许多 尝试正确设置标题。我 60% 确信此时将通过 serverless.yml
文件进行修复。
"use strict";
const spongebobify = require("spongebobify");
module.exports.endpoint = (event, context, callback) =>
let startLower = event.headers.startlower === "false" ? false : true;
try
const response =
statusCode: 200,
headers:
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Headers": "content-type,origin,text,startlower",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"content-type": "text/plain",
"Access-Control-Allow-Credentials": true // Required for cookies, authorization headers with HTTPS
,
body: spongebobify(event.headers.text, startLower)
;
callback(null, response);
catch (err)
console.log(err);
const response =
statusCode: 403,
headers:
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Headers": "content-type,origin,X-text,startlower",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"content-type": "text/plain",
"Access-Control-Allow-Credentials": true // Required for cookies, authorization headers with HTTPS
,
body: "Malformed request."
;
callback(null, response);
;
您可以复制我在以下站点的开发控制台中运行上述XMLHttpRequest
的问题:
-
api.spongebobify.com 启用或禁用自定义标头。它在这两种情况下都能完美运行(因为它不会是跨源的)。
任何没有正确配置 CSP 并启用自定义标头的站点。 OPTIONS 请求会失败,它会准确报告没有 Access-Control-Allow-Origin 标头
没有正确配置 CSP没有启用自定义标头的任何站点。 OPTIONS 请求将通过(您会知道,因为 Chrome 永远不会告诉您它发生了),您将在响应标头中看到 Access-Control-Allow-Origin。您还将看到响应“格式错误的请求”。
【问题讨论】:
我对无服务器一无所知,但通过查看问题中的 serverless.yml 文件,我看到了用于处理 GET 请求的配置,但没有任何用于处理 OPTIONS 请求的配置。要获取 cors 配置,您不需要显式处理对该文件的 OPTIONS 请求吗? 一开始我也是这么想的——Serverless 文档中没有任何关于它的内容,而且它似乎可以在没有自定义标头的情况下很好地处理 OPTIONS,所以我怀疑就是这样。 问题是,如果没有将自定义标头添加到请求中,您的浏览器就没有执行 OPTIONS 请求。xhr.setRequestHeader("text", "hey")
代码是导致浏览器发送 OPTIONS 请求的原因。当您删除它时,浏览器只是直接发送 GET 请求,而无需先执行任何 OPTIONS 预检。
它不是必须首先发送一个 OPTIONS 请求来验证域是否对 CORS 请求开放吗?
否 - 请参阅 developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests。您的无添加标头 GET 请求是一个不需要预检的“简单请求”
【参考方案1】:
问题是Prefilght request 是如何工作的,根据我的经验,这个过程不能很好地仅在 GET 方法上配置自定义标头,因此,只需添加 POST 方法并修复 CORS 问题:
events:
- http:
path: admin/type
method: get
cors:
origin: '*'
headers:
- token
allowCredentials: false
- http:
path: admin/type
method: post
cors:
origin: '*'
headers:
- token
allowCredentials: false
这个CORS and API Gateway survival guide 和Fixing Common Problems with CORS and javascript 帮助我理解问题和解决方案。
这是我的 JS 代码
fetch(api_url,
method : 'GET',
mode: 'cors',
headers:
token: 'XXXX-XXXX'
).then((resp) => resp.json())
【讨论】:
【参考方案2】:我认为问题在于您将 HTTP 事件的短格式 (- http: GET /
) 与添加其他选项的长格式混合在一起。
试试这个:
functions:
app:
handler: handler.endpoint
events:
- http:
method: GET
path: /
cors:
origin: '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- Startlower
- Text
- Access-Control-Allow-Headers
- Access-Control-Allow-Origin
allowCredentials: false
主要变化有:
1) 在http
事件对象上添加method
和path
键,以及
2) 将cors
对象缩进另一个级别。它之前位于http
事件的顶层。
如果这有帮助,请告诉我:)
【讨论】:
这确实有效 - 尽管我只是从标题切换到查询参数,因为它让我的生活变得更轻松。不过谢谢! 是否可以为事件中的每个请求定义这些标头或所有请求? @亚历克斯以上是关于如何在无服务器中允许 CORS 用于自定义标头?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Google Cloud Endpoints 中允许 CORS?