如何使用代理 Lambda 从 API Gateway 发送多个 Set-Cookie 标头

问题描述 投票:0回答:7

我正在使用 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
7个回答
27
投票

注意: API 网关现在具有版本 2 有效负载,该有效负载与此处描述的有效负载(以及新 API 的默认值)根本不同。有关差异的文档此处。有关更多详细信息,请参阅塞缪尔其他接受的答案。

自 2018 年 11 月起,可以在响应中使用

multiValueHeaders
字段代替
headers
(请参阅公告)。

作为示例而不是:

{
  "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"]
  }
}

请注意,您可以混合使用

headers
multiValueHeaders

{
  "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
下的值被删除。

请参阅文档了解更多详细信息。

仅使用标头字段(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
掉在了地板上。


10
投票

请注意,在 09/2022 中,AWS Api Gateway 默认使用新的有效负载格式(版本 2.0),该格式不再识别所有热门答案(包括已接受的答案)所提议的

multiValueHeaders
。我只是花了 40 分钟试图找出为什么它不返回我的 cookie:)。

来自 AWS 文档:

Format 2.0 没有 multiValueHeaders 或 multiValueQueryStringParameters 字段。合并重复的标头 用逗号并包含在标题字段中。重复的查询字符串 用逗号组合并包含在 queryStringParameters 中 领域。

格式 2.0 包含一个新的 cookies 字段。中的所有 cookie 标头 request 用逗号组合并添加到 cookies 字段中。在 对客户端的响应,每个 cookie 都成为一个 set-cookie 标头。

https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html

所以现在实际的解决方案应该是:

    return {
      statusCode: 302,
      headers: {
        Location: location,
      },
      cookies: [
         "cookie1=value1;",
         "cookie2=value2;"
      ]
    };

8
投票

正如所回答的,迄今为止,API 网关将删除相同的密钥,仅设置其中一个 cookie。

但是,存在一种解决方法。您可以更改字符串

'Set-Cookie'
的大小写,这样键就不是唯一的。例如,您可以使用键
set-cookie
Set-cookie
sEt-cookie
,标头将被保留,并且将设置 3 个不同的 cookie。

因为 RFC 标准使标头不区分大小写,这应该适用于所有符合 RFC 的客户端。

因此,您可以重写 set-cookie 标头,排列“Set-Cookie”的所有可能大小写来解决此问题。

这项技术(黑客)被 Zappa 采用,这是一种用 Python 编写的流行无服务器框架。


4
投票

使用多值标头:

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


3
投票

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

Cookie: a=1; b=2

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


0
投票

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

...

//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>");

0
投票

对于使用 API Gateway V2 的用户,您可以使用

cookies
属性发送多个 cookie。

// Make sure to import V2 types from aws-lambda pacakge
import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from "aws-lambda";

export async function lambda(event: APIGatewayProxyEventV2): Promise<APIGatewayProxyResultV2> {
  return {
    headers: {
      "Content-Type": "application/json"
    },
    cookies: ["cookie1=value", "cookie2=value"], // Provide cookies
    body: JSON.stringify("{ isAuthenticated: true }"),
    statusCode: 200,
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.