无服务器 Lambda 和 API 网关的 CORS 问题

CORS issues with Serverless Lambda and API Gateway

已解决

以下问题完全是由在我的 Lambda 中构建的响应 object 的 body 属性 引起的。我忘记对数据进行字符串化,返回 body: data 而不是 body: JSON.stringify(data)。这个响应问题似乎触发了 API 网关的错误,导致请求失败并出现一些相当混乱的错误消息。

问题

我正在使用 React、Serverless 和 Stripe 开发电子商务网站 API。我的 front-end React 应用程序正在使用 Axios 向我的 Lambda 函数发出 GET 请求,该函数已通过 API 网关公开。 Lambda 函数依次查询 Stripe API 和 returns Stripe 响应数据到我的 React 应用程序。但是,当我的 React 应用程序尝试调用 Lambda 时,我遇到了 CORS 问题,它收到以下错误:

Failed to load: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 502.

查询 Insomnia 中的 Lambda 端点 returns 502 响应 { "message": "internal server error" }。但是从终端成功地从 Lambda 函数执行 serverless invoke 命令 returns Stripe 数据。

我正在为我的 serverless.yml 文件中的函数启用 cors,并按照 this Serverless blog post, I have also attempted adding a various combinations of the following headers to my Lambda response and my Axios request based on suggestions found on this issue on Axios and this issue on Serverless 中的建议在我的 Lambda 代码响应中包含 'Access-Control-Allow-Origin': '*'。我已多次删除并重新部署该服务

Lambda 响应 headers

headers: {
      'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
      'Access-Control-Allow-Credentials': true,
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
    },

React/Axios 配置

  {
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    crossDomain: true
  }

目前我的代码如下:

React 应用程序

import Axios from 'axios';
import { GET_PRODUCTS_URL } from '../config';

export default () => {
  return Axios
  .get(GET_PRODUCT_URL, {
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    crossDomain: true
  })
  .then(({ data }) => data)
  .catch(console.log);
}

拉姆达

import Stripe from 'stripe';
const apiKey = process.env.STRIPE_SECRET_KEY;

const stripe = Stripe(apiKey);

module.exports.handler = (event, context, callback) => {
  return stripe.products
    .list()
    .then(({ data }) => {
      const response = {
        statusCode: 200,
        headers: {
          'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
          'Access-Control-Allow-Credentials': true,
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
        body: data,
      };
      callback(null, response);
    })
    .catch(console.log);
}

Serverless.yml

service: srd

provider:
  name: aws
  runtime: nodejs6.10
  stage: ${opt:stage, self:custom.defaultStage}
  region: eu-west-1
  memorySize: 256
  timeout: 6
  versionFunctions: true

plugins:
  - serverless-plugin-optimize
  - serverless-plugin-scripts

package:
  individually: true

functions:
  get-products:
    handler: lambda/get-products.handler
    name: srd-get-products-${self:provider.stage}
    description: 'get srd products from stripe'
    environment:
      STRIPE_PUBLISHABLE_KEY: ${self:custom.stripe_publishable_key.${self:provider.stage}}
      STRIPE_SECRET_KEY: ${self:custom.stripe_secret_key.${self:provider.stage}}
    events:
      - http:
          path: products
          method: get
          cors: true

custom:
  defaultStage: dev
  stripe_publishable_key:
    dev: ${file(env.yml):STRIPE_DEV_PUBLISHABLE_KEY}
    live: ${file(env.yml):STRIPE_LIVE_PUBLISHABLE_KEY}
  stripe_secret_key:
    dev: ${file(env.yml):STRIPE_DEV_SECRET_KEY}
    live: ${file(env.yml):STRIPE_LIVE_SECRET_KEY}

我已经在这里工作了几个小时,非常感谢任何见解。

Edit/Additional 从 CLI returns 发出以下选项请求:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Date: Mon, 19 Mar 2018 06:52:12 GMT
x-amzn-RequestId: 0d10c9d1-2b42-11e8-b270-a723e367048e
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
Access-Control-Allow-Methods: OPTIONS,GET
Access-Control-Allow-Credentials: false
X-Cache: Miss from cloudfront
Via: 1.1 e40b14deb4a844594f746b751f632677.cloudfront.net (CloudFront)
X-Amz-Cf-Id: eMvu3Ke7m7GNFCFgIOGVJmoObFwYMeEt4o8AByoipfMn1nXIi9Vo0g==

CORS 错误消息中的 HTTP 响应代码为 502。这意味着您请求的服务器不可用。

在 502 事件中,浏览器无法发出成功的 OPTIONS 请求,因此即使您在服务器中的 CORS 设置正确,您仍然会收到 CORS 错误,因为它没有正确解析。

查看您的服务器并确保它 运行 正常。一旦修复了 502 错误,请重试,您应该可以开始了。尝试手动发出 OPTIONS 请求,类似于浏览器发出的请求,看看是否会出现相同的错误。