调用源自浏览器AWS开发工具包时,AWS Lambda设置响应标头

时间:2019-04-26 00:57:17

标签: javascript amazon-web-services aws-lambda aws-sdk-js

通过具有AWS Lambda代理集成的API Gateway设置响应标头很简单,如下所示:

import zlib from 'zlib';

exports.handler = async (event, context, callback) => {
  const body = zlib.gzipSync(JSON.stringify({ data: 'mock' }));

  const headers = {};
  headers['Content-Type'] = 'application/json';
  headers['Content-Encoding'] = 'gzip';

  const responseObject = {
    statusCode: 200,
    headers,
    body: body.toString('base64'),
    isBase64Encoded: true
  };

  return callback(null, responseObject);
}

所有内容均按预期返回。因为我们设置了内容编码,所以浏览器解压缩了响应。

问题是,当使用AWS开发工具包JS直接从浏览器中调用Lambda函数时,如何设置标头? API Gateway是一项服务,该服务实现了先前设置中的标头,而没有在AWS Lambda标头前面放置API Gateway,并且标头通常设置为:

access-control-allow-origin: *
access-control-expose-headers: x-amzn-RequestId,x-amzn-ErrorType,x-amzn-ErrorMessage,Date,x-amz-log-result,x-amz-function-error
content-length: 1242
content-type: application/json
date: Fri, 26 Apr 2019 00:36:35 GMT
status: 200
x-amz-executed-version: $LATEST
x-amzn-remapped-content-length: 0
x-amzn-requestid: <REDACTED>
x-amzn-trace-id: <REDACTED>

AWS SDK JS浏览器调用代码如下所示:

import AWS from 'aws-sdk';

AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: '<SOME IDENTITY>',
});

const AWSLambda = new AWS.Lambda({region: REGION, apiVersion: '2015-03-31'});

const parameters = {
    FunctionName : 'MyFunctionName',
    InvocationType : 'RequestResponse',
    LogType : 'None',
    Payload: JSON.stringify({msg: 'hello lambda'})
};

(async () => {
  const response = await AWSLambda.invoke(shopParameters).promise();
  console.log(response);
})();

返回的响应是上面的响应对象,是带有通用标头的字符串。浏览器不会解压缩压缩后的内容,大概是因为未设置内容编码标头。从浏览器调用时,AWS Lambda会将整个Lambda响应对象视为响应,并且不会执行API Gateway发生的任何转换。例如,API Gateway会选择响应对象的结构,并将响应对象标头映射到响应,然后再发送给客户端。

如果没有API Gateway,是否无法设置AWS Lambda标头?或者是使用https://github.com/nodeca/pako之类的在客户端上手动解压缩gzip内容的唯一选项(叹气)。

不使用API​​网关的想法来自此处找到的AWS文档,以避免API网关成本:https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/browser-invoke-lambda-function-example.html

非常感谢任何指导,专业知识和思想!

2 个答案:

答案 0 :(得分:3)

否,在Lambda服务API(通常是API网关)前面没有东西的情况下,无法执行此操作。

您的const responseObject实际上是使用API​​网关指定的格式创建响应的-Lambda服务不对响应进行任何解释。这就是为什么它对响应中的标头没有影响,以及为什么base64保持未翻译的原因-整个结构是特定于API网关的。 Lambda只是返回JSON。

如果响应足够小,则“某物”可能会是Application Load Balancer,尽管身份验证会有所不同,但使用with Cognito可能会或不太容易。它使用与API网关基本相同的响应格式,并且平衡器在将base64返回给浏览器之前对其进行解码。

您还可以使用CloudFront的Lambda@Edge功能通过HTTP(S)调用Lambda函数,并设置自定义标头并自动解码base64,但是此服务没有内置的Cognito集成,并且明显不同而不是功能齐全的Lambda服务,它仅支持Node.js并在离浏览器最近的AWS区域(而不是在创建该区域以提高全局性能的区域)中运行Lambda函数。 Lambda @ Edge还期望使用不同的输出格式,这是比API Gateway期望的响应结构更精心设计的设计,但因此也不能互换。

答案 1 :(得分:1)

或者,根据您的要求,我使用的一种策略是让lambda将json写入s3,在s3上将其公开,并且可以轻松获取。