【问题标题】:How can I send multiple Set-Cookie headers from API Gateway using a proxied Lambda如何使用代理 Lambda 从 API Gateway 发送多个 Set-Cookie 标头
【发布时间】:2017-02-07 17:10:40
【问题描述】:

我正在使用 API Gateway 的代理集成来调用 Lambda。输出格式规范如下 JSON 格式:

{
  "statusCode": httpStatusCode,
  "headers": { "headerName": "headerValue", ... },
  "body": "..."
}

在一个响应中,我希望设置两个 cookie(两个不同的身份验证 cookie),但 JSON 不允许在 headers 对象中有两个相同的键(好吧,从技术上讲,规范可以,但大多数库没有)。

RFC 7230 注意到 Set-Cookie 应该进行特殊处理,但我看不到如何通过 API 网关发送多个 Set-Cookie 值。

有人知道这是否可能吗?

【问题讨论】:

    标签: json amazon-web-services cookies aws-lambda aws-api-gateway


    【解决方案1】:

    从 2018 年 11 月起,可以在响应中使用 multiValueHeaders 字段而不是 headers(请参阅 announcement)。

    作为一个例子而不是:

    {
      "statusCode": 200,
      "body": "testing multiple set-cookie headers",
      "headers": {
        "X-Test-Header": "baking experiment",
        "Set-Cookie": "cookie1=chocolate-chip",
        "Set-Cookie": "cookie2=oatmeal",
        "Content-Type": "text/plain"
      }
    }
    

    您可以回复:

    {
      "statusCode": 200,
      "body": "testing multiple set-cookie headers",
      "multiValueHeaders": {
        "X-Test-Header": ["baking experiment"],
        "Set-Cookie": ["cookie1=chocolate-chip", "cookie2=oatmeal"],
        "Content-Type": ["text/plain"]
      }
    }
    

    请注意,您可以混合使用headersmultiValueHeaders

    {
      "statusCode": 200,
      "body": "testing multiple set-cookie headers",
      "headers": {
        "X-Test-Header": "baking experiment",
        "Content-Type": "text/plain"
      },
      "multiValueHeaders": {
        "Set-Cookie": ["cookie1=chocolate-chip", "cookie2=oatmeal"]
      }
    }
    

    但是在两者中使用相同的标头将意味着headers 下的值被删除。

    有关详细信息,请参阅documentation

    当仅使用标头字段(2018 年 11 月之前可用)时,我尝试发送以下手动管理的 JSON 作为响应:

    {
      "statusCode": 200,
      "body": "testing multiple set-cookie headers",
      "headers": {
        "X-Test-Header": "baking experiment",
        "Set-Cookie": "cookie1=chocolate-chip",
        "Set-Cookie": "cookie2=oatmeal",
        "Content-Type": "text/plain"
      }
    }
    

    API 网关响应 CURL 请求返​​回的 cookie 是:

    < Content-Type: text/plain
    < Content-Length: 35
    < Connection: keep-alive
    < Date: Thu, 29 Sep 2016 11:22:09 GMT
    < Set-Cookie: cookie2=oatmeal
    < X-Test-Header: baking experiment
    < X-Cache: Miss from cloudfront
    

    如您所见,第一个 Set-Cookie 掉在了地板上。

    【讨论】:

    • @MarkB 这不是真的,see rfc6265。您需要能够使用多个 Set-Cookie 标头进行响应,因为每个 cookie 可能具有不同级别的 cookie 安全性、过期等。
    • 我认为理想情况下 AWS 会使用 the Headers interface of the Fetch APIHeaders 实例允许您使用headers.append(key, value),这意味着您可以多次设置Set-Cookie 标头。然后,您可以调用 Lambda 回调,其 headers 属性等于普通对象 Headers 实例。
    【解决方案2】:

    正如回答的那样,迄今为止,API Gateway 将丢弃相同的密钥,只设置一个 cookie。

    但是,存在一种解决方法。您可以更改字符串 'Set-Cookie' 的大小写,因此键不是唯一的。例如,您可以使用键 set-cookieSet-cookiesEt-cookie,并且会保留标头并设置 3 个不同的 cookie。

    因为 RFC 标准使标头 case-insensitive 这应该适用于所有符合 RFC 的客户端。

    因此,您可以重写您的 set-cookie 标头 permuting all the possible casings of "Set-Cookie" 来解决这个问题。

    这种技术(hack)是employed by Zappa,一个用 Python 编写的流行的无服务器框架。

    【讨论】:

    • 刚刚看到这个,显然现在已经正确修复,但谁认为这个黑客应该得到一个独角兽。杰出的。 ? 感谢@sytech 引起我的注意
    【解决方案3】:

    使用 multiValueHeaders:

    response.multiValueHeaders = {
      "Set-Cookie": [
        'cookie1=value1',
        'cookie1=value1'
      ]
    }
    

    或:

    {
        "statusCode": httpStatusCode,
        "headers": { "headerName": "headerValue", ... },
        "multiValueHeaders": { "headerName": ["headerValue", "headerValue2",...], ... },
        "body": "..."
    }
    

    https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format

    【讨论】:

      【解决方案4】:

      晚了几年,但我只需要实现这样的东西,这就是我能够使它工作的方式:

      ...
      
      //15 minutes
      var expirationTime = new Date(new Date().getTime() + 15 * 60 * 1000);
      //30 minutes
      var expirationTime2 = new Date(new Date().getTime() + 30 * 60 * 1000);
      
      var response = {};
      
      var cookies = [];
      cookies.push("testCookie={'keyX':'valx', 'keyy':'valy'}; Expires=" + expirationTime + ";");
      cookies.push("testCookie2={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + ";");
      
      response.headers["Set-Cookie"] =  cookies;
      
      ...
      

      每个数组项都将被独立处理,因此您可以使用不同的设置向数组中添加尽可能多的 cookie。

      cookies.push("testCookie3={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + "; Max-Age=...");
      
      cookies.push("testCookie4={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + "; Domain=<domain-value>; Path=<path-value>");
      

      【讨论】:

        【解决方案5】:

        正如 Mark B 所指出的,您可以/应该通过在单个 Set-Cookie 标头中设置多个 cookie 名称/值对来实现此目的。浏览器应该能正确解释这一点。

        Cookie: a=1; b=2
        

        编辑:正如 OP 所指出的,有些用例需要标头的多个实例。我们已将其添加到我们的待办事项中,并支持传入请求的多个标头名称。

        【讨论】:

        • See rfc6265。您需要能够使用多个 Set-Cookie 标头进行响应,因为每个 cookie 可能具有不同级别的 cookie 安全性、过期等。
        • 我明白了,好点子。我必须将其添加到我们的待办事项中;如果我们必须更改从 Lambda 返回的形状并接受这两种格式,可能需要一段时间。
        • 建议的Set-Cookie 不是对标头的有效使用。您只能为每个标头设置一个 cookie(与从浏览器发送的 Cookie 不同,它的工作原理与您上面所说的完全一样)。第一个; 之后的所有内容都被解释为到期、最大年龄等选项。请参阅the RFC 中的语法。
        • 我刚刚用 Chrome 试过这个。当 Chrome 接收到 Set-Cookie": "cookie1=chocolate-chip; cookie2=oatmeal 的标头时,Chrome 会设置 cookie1=chocolate-chip 并丢弃无效属性——据我所知,它遵循 RFC。您的更新根本不起作用 - Cookie 标头从浏览器发送到服务器,而不是从服务器发送到浏览器(在每次方法调用时将所有累积的 cookie 发送回服务器)。
        • 你好,这个现在是什么状态?
        猜你喜欢
        • 2021-05-22
        • 1970-01-01
        • 1970-01-01
        • 2022-10-06
        • 1970-01-01
        • 2021-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多