如何通过API网关从Lambda正确返回二进制文件(图像)

6

这是我的lambda表达式:

exports.handler = async (event) => {
    const hex = '89504e470d0a1a0a0000000d49484452000000a0000000a00800000000aea438f10000053e4944415478daed99bd6b2a4d1487effff4834504610988208204040b411002161616818010b0b0106e110b411041d258a4b0085858489a142902172e046c2c445208161224582c72dec29dd98fd911a2ee7a7939db654edc3c998fe79c39fea27ffcf9c5800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc8800cc880ff4bc09bab4cae58aed61a0f9dc741bfdb6adc554ab974d24c2d699b3693d962b5d668f506bd76b37e5b29e5b3c9d42759d99899ce97ef1aed6eb7ddac550a693356209a18f1ab6cb15a7fe8f43aad7ab5983163b9d30153d03c7f68630406de6811309a27eaa9a3d7a7037e34f3011c66b9f54df4524b2b7ff1b6bda1dde37dc1331a2fb5a6449fedbb8c7bd4283ccccfb20737936b2f457a6889d8bce20edccde48766b772343392bfbe1bcb7fc9e86cce7748ac41dc859159bb6343179f7b7c27d0db967b781ab3977c7ede53fcee22fceb0db565e0c5fb91fd60d7f7a6fa7e1156e7d6ccb3c448ec7cd39b1391b1776700006efd2f1ad827e9ec1e947b4a51c39b88fcf60c2f0120f9e5ffed2100d44310f522268ea4e50f89dd76b5758fbeaaab2e76447c194626f92d266aa2a8484446eed11a806a80f995a93e17e0a7f06185745398778dad0cc0508feada008ccf7072714d4c94f267df45e4d5196b05cfd400402da462e1afc0682aa1a21d293a131807126bf525d7aaa7ce57cd88fc955072c044b0bfbb776c477dc51b804268e59674e1c01fd9896458168e8901e6265856a3d000b7a68d91dd05da0d003ef63f3700f4d5372c0d20698557b0b6020e83cd9eb423fbccb13080d4960225d809b1a23e609abe609f1111dd03780a283a9280b10a1190aa5ad37c25ecc83d11cd0c2013b092633b1e1ee09bde340fa2cefbd41f8592b349c3ba345d6b4db33424fb14406ea77e78ea3165388003ad69ec420f88ad2a4109db3edaa390013709ad696682bdac91f126fe43c71c752f6e6a4de39c204d413a08a8afcf0f28e74935cd1f87ef46b37f7fe698e33a0b65ad6964c900fcd118e09ec2079ce84d234365dd9de12302402bad358d2c19d256701a2e5204804e52534d330cacfdf74f47b9f68505b88e694d234b0655d3561248599100d2bdde347dedc56a0ca017517ff0436f1a192a045ce662ab88001d9d28a6b9d3997af693dbfac980239d69668eaacb6a1a9e4606b8bdd298e6169a16d3260194283240a7a1355076a05cfeaa3f0d8f230494b59fd73415c058543cb5bffde48e72ccf180ce5abefa2ef64da7cb50f3761e7a1425e07b9069ca407ce59c7163e13edcb175a48094534df30ea0ed2e191aee3e529da2057c524d7303985f44b4cbcadadf9586a711037e27fca67903f0e82d191eec349cd254b061023aedcc81935eec5e822c19eceed65873870a17700eaf695e000cfd254357ac7dda8a1c5076556dd3e4816bcbdf6530bfedfcd7a7e8015f3ca6997896b1e55eff26105f5f00709771996697f3545832d3a42cda248e76cc6980f4e8fa7a64e42bb0449701437a3ade312702aee3d23456d6575fc9ba2b6be58e77cc8980ce340d9e951ba5ec32344e70cca98053394d19df379d9e2ec3f18e3915904aae2fa7e7fa589f2e053876201a5a0b9de0989301ada48458eaeb9d065d0c903a02a2a5c69e832aeba80157b690cd8055b452071a4951018a7b70ff80c85f2e0ab8b749721b14db980090de5d1490f208feca465e4e1fe9b2804300598d88573120fe7561c0ad79e046de38d131e700a4ee81526061c6e71707a4e58153f0bda1cb0386fb30200332200332200332200332200332200332200332200332200332200332200332200332e03ffafc0761478d7dbc33444a0000000049454e44ae426082'

    const image = Buffer.from(hex, 'hex');

    const result = /* "data:image/png;base64," + */ image.toString('base64');

    const response = {
        statusCode: 200,
        headers: {
            'Content-Type': 'image/png'
        },
        body: result,
        isBase64Encoded: true
  }


    return response;
};

这将会作为JSON返回。

接下来,在API Gateway中,GET - 集成响应:

我通过AWS控制台设置如下: Content handling: Convert to binary (if needed)

标头映射: Content-Type: 'image/png'

映射模板: image/png。目前我使用的是:

{
    "base64Image": $input.path('$.body')
}

最后,在GET方法响应中:

200的响应头名称:Content-Type

200的响应体内容类型:image/png,模型类型为:Empty

二进制媒体类型已启用,使用的类型为:image/png.

遗憾的是,方法执行失败:

Mon Sep 23 09:52:37 UTC 2019 : Endpoint response body before transformations: {"statusCode":200,"headers":{"Content-Type":"image/png"},"body":"iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAAAAACupDjxAAAFPklEQVR42u2ZvWsqTRSH7//0g0UEYQmIIIIEBAtBEAIWFhaBgBCwsBBuEQtBEEHSWKSwCFhYSJoUKQIXLgRsLERSCBYSJFgsct7CndmP2RGi7np5OdtlTtw8mY/nnDn+on/8+cWADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiADMiA/0vAm6tMrliu1hoPncdBv9tq3FVKuXTSTC1pmzaT2WK11mj1Br12s35bKeWzydQnWdmYmc6X7xrtbrfdrFUKaTNWIJoY8atssVp/6PQ6rXq1mDFjudMBU9A8f2hjBAbeaBEwmifqqaPXpwN+NPMBHGa59U30Uksrf/G2vaHd433BMxovtaZEn+27jHvUKDzMz7IHN5NrL0V6aInYvOIO3M3kh2a3cjQzkr++G8t/yehszndIrEHchZFZu2NDF597fCfQ25Z7eBqzl3x+3lP87iL86w21ZeDF+5H9YNf3pvp+EVbn1syzxEjsfNObE5Gxd2cAAG79LxrYJ+nsHpR7SlHDm4j89gwvASD55f/tIQDUQxD1IiaOpOUPid12tXWPvqqrLnZEfBlGJvktJmqiqEhERu7RGoBqgPmVqT4X4KfwYYV0U5h3ja0MwFCP6toAjM9wcnFNTJTyZ99F5NUZawXP1ABALaRi4a/AaCqhoh0pOhMYBxJr9SXXqqfOV82I/JVQcsBEsL+7d2xHfcUbgEJo5ZZ04cAf2YlkWBaOiQHmJlhWo9AAt6aNkd0F2g0APvY/NwD01TcsDSBphVewtgIOg82etCP7zLEwgNSWAiXYCbGiPmCavmCfERHdA3gKKDqSgLEKEZCqWtN8JezIPRHN [TRUNCATED]
Mon Sep 23 09:52:37 UTC 2019 : Execution failed due to configuration error: Unable to transform response
Mon Sep 23 09:52:37 UTC 2019 : Method completed with status: 500

我的配置有什么问题?我漏掉了什么地方吗?

我希望得到的是返回二进制文件的image/png

2个回答

6
如果您正在使用Express和Serverless,以下内容适用于您:
安装serverless-apigw-binary插件:
npm install --save-dev serverless-apigw-binary
确保已安装serverless-http:
npm i serverless-http 这里的答案帮助我在Express中返回一个base-64图像: Express send base-64 encoded png-image 这是我的app.js文件。请注意,您必须在module.exports.handler中引用二进制文件:
const serverless = require("serverless-http");
const express = require("express");
const app = express();

app.get('/', function (req, res){
   var dataUrl = "data:image/png;base64,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";
   var dataUrlEdit = dataUrl.replace(/data:image\/png;base64,/, '');
   var img = Buffer.from(dataUrlEdit, 'base64');
   res.writeHead(200, {
     'Content-Type': 'image/png',
     'Content-Length': img.length
   });
   res.end(img);
})

module.exports.handler = serverless(app, {
    binary: ['image/png', 'image/gif']
  });

这是我的serverless.yml文件:

service: your-app

provider:
  name: aws
  runtime: nodejs10.x
  stage: dev
  region: us-east-1

functions:
  app:
    handler: app.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

plugins:
  - serverless-apigw-binary

custom:
  apigwBinary:
    types:
      - '*/*' 

感谢tomyates在这里的回答:

https://github.com/dougmoscrop/serverless-http/issues/34


我在浏览器中遇到了一个问题,无法正确地渲染响应图像,所以在 serverless.yml 文件中,我明确设置了 types: - 'image/jpeg',而不仅仅是 types: - '*/*',这样就解决了问题。 - Petr Bela
这应该是被接受的答案。使用 expressjs,在 netlify-lambda 中完美运行。 - robe007
@robe007 并不是每个人都在使用ExpressJS。 - iaforek
@iaforek 我只是在评论客户使用的东西。 - robe007

5
需要三个主要步骤:
  1. Lambda 必须将图像作为 base64 编码的字符串返回:return image.toString('base64')
  2. 在 API Gateway > 方法执行 > 集成请求 > 映射模板中 - 添加:Content-Type: image/png
  3. 在 API 设置中启用二进制媒体类型并将其设置为 image/png

部署 API 并在 POSTMAN 中使用以下标头调用端点 URL:Accept: image/pngContent-Type: image/png

就这样。这将正确地以图像形式返回该图像!

如果有人需要更多细节,我已经创建了一个完整的教程,逐步介绍每个步骤:https://medium.com/@iaforek/how-to-configure-binary-support-in-api-gateway-the-easy-and-working-way-ac2d68face36

最重要的是,你无需像其他博客文章建议的那样使用 CONVERT_TO_BINARY 透传。


我需要帮助从Lambda返回PDF的图像部分。我有一个Java Lambda已部署,它正在通过XSL FO呈现数据并生成PDF,并作为JSON返回。但是在XSL中作为base64存在的图像未作为PDF(base64编码)响应的一部分出现。 - upadhyayRakes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接