通过 AWS API Gateway 和 Lambda 函数返回动态内容类型

kin*_*l68 4 lambda content-type amazon-web-services aws-lambda aws-api-gateway

我想使用 AWS API 网关作为从 S3 存储桶中获取文件并将它们返回给客户端的代理。我正在使用 Lambda 函数与 S3 通信并通过 AWS API 网关将文件发送到客户端。我认为最好的方法是使用“Lambda 代理集成”,这样整个请求无需任何修改就可以通过管道传输到 Lambda。但是,如果我这样做,则无法为来自我的 Lambda 函数的结果响应设置集成响应。所以客户端得到的只是 JSON。

似乎 API 网关应该有一种方法来获取 JSON 并将请求转换为客户端的正确响应,但我似乎无法弄清楚如何实现这一点。有很多示例指向手动设置来自 API 网关的响应的内容类型,但我需要将内容类型标头设置为任何文件类型。

同样对于图像和二进制格式,我的 Lambda 函数返回一个 base64 编码的字符串,并且属性isBase64Encoded设置为true. 当我转到“二进制支持”部分并指定类似image/*应作为二进制返回的内容类型时,它不起作用。我只有通过将二进制支持内容类型设置为*/*(也称为所有内容)才能成功,这对非二进制内容类型不起作用。

我错过了什么,为什么这看起来如此困难?

kin*_*l68 5

结果证明 API Gateway 不是问题。我的 Lambda 函数没有返回正确的标头。

为了处理二进制响应,我发现您需要将 Binary Support 内容类型设置为*/*(也称为所有内容),然后让您的 Lambda 函数将属性isBase64Encoded设置为true. 以 base64 编码并指示的响应将被解码并以二进制形式提供,而其他请求将按原样返回。

这是 Lambda 函数的一个简单 Gist,它采用给定路径并从 S3 读取文件并通过 API 网关返回它:

/**
 * This is a simple AWS Lambda function that will look for a given file on S3 and return it
 * passing along all of the headers of the S3 file. To make this available via a URL use
 * API Gateway with an AWS Lambda Proxy Integration.
 * 
 * Set the S3_REGION and S3_BUCKET global parameters in AWS Lambda
 * Make sure the Lambda function is passed an object with `{ pathParameters : { proxy: 'path/to/file.jpg' } }` set
 */

var AWS = require('aws-sdk');

exports.handler = function( event, context, callback ) {
    var region = process.env.S3_REGION;
    var bucket = process.env.S3_BUCKET;
    var key = decodeURI( event.pathParameters.proxy );

    // Basic server response
    /*
    var response = {
        statusCode: 200,
        headers: {
            'Content-Type': 'text/plain',
        },
        body: "Hello world!",
    };
    callback( null, response );
    */

    // Fetch from S3
    var s3 = new AWS.S3( Object.assign({ region: region }) );
    return s3.makeUnauthenticatedRequest(
        'getObject',
        { Bucket: bucket, Key: key },
        function(err, data) {
            if (err) {
                return err;
            }

            var isBase64Encoded = false;
            if ( data.ContentType.indexOf('image/') > -1 ) {
                isBase64Encoded = true;
            }

            var encoding = '';
            if ( isBase64Encoded ) {
                encoding = 'base64'
            }
            var resp = {
                statusCode: 200,
                headers: {
                    'Content-Type': data.ContentType,
                },
                body: new Buffer(data.Body).toString(encoding),
                isBase64Encoded: isBase64Encoded
            };

            callback(null, resp);
        }
    );
};
Run Code Online (Sandbox Code Playgroud)

通过https://gist.github.com/kingkool68/26aa7a3641a3851dc70ce7f44f589350