如何在无服务器中为自定义标头提供CORS?

时间:2017-12-28 06:23:05

标签: node.js lambda cors serverless-framework serverless

这里的核心问题是:“如何在使用无服务器框架处理的CORS GET请求中允许自定义标头?”。如果您知道答案,请通过Go,收取200美元并回答该问题。如果这不是一个直接答案的问题,这里有详细信息:

我正在使用AWS Lambda上的无服务器框架编写应用程序(该API通过AWS API Gateway进行管理。坦率地说,我不完全确定这意味着什么或者提供了什么好处,但这就是无服务器为我自动配置的内容)。我正在尝试创建一个开放的API,需要启用CORS。我正在使用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.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来复制我的问题:

  1. api.spongebobify.com启用或禁用自定义标头。它在两种情况下都能完美地工作(因为它不会是交叉原点)。
  2. 任何未正确配置CSP且启用了自定义标头的网站。 OPTIONS请求将失败,它将准确报告没有Access-Control-Allow-Origin标头
  3. 未启用自定义标头的任何未正确配置的CSP 的网站。 OPTIONS请求将通过(您将知道,因为Chrome永远不会告诉您它发生了),您将在响应标头中看到Access-Control-Allow-Origin。您还会看到响应“格式错误的请求。”。

1 个答案:

答案 0 :(得分:6)

我认为问题在于您正在将简短形式的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)在method事件对象上添加pathhttp个键,然后

2)将cors对象缩进到另一个级别。它之前处于http事件的顶层。

请告诉我这是否有帮助:)