AWS Java Lambda 压缩 JSON 响应失败:“由于配置错误,执行失败:格式错误的 Lambda 代理响应”

Posted

技术标签:

【中文标题】AWS Java Lambda 压缩 JSON 响应失败:“由于配置错误,执行失败:格式错误的 Lambda 代理响应”【英文标题】:AWS Java Lambda compressed JSON responses fails: "Execution failed due to configuration error: Malformed Lambda proxy response" 【发布时间】:2019-09-16 14:03:15 【问题描述】:

我正在从 AWS API Gateway 调用 AWS Lambda 函数。返回的 JSON 需要压缩,因为它有时会变得太大(主体尺寸太大等)。但是,我在通过 API 网关获取响应时遇到了一些问题。这是我的 Java 代码:

    @Override
    public JSONObject handleRequest(Object input, Context context) 
        String json_string = "";
        try 
            Gson gson = new Gson();
            json_string = gson.toJson(input, LinkedHashMap.class);
         catch (ClassCastException ex) 
            json_string = (String) input;
        

        GenerateJson generateJson = new GenerateJson ();
        String body = "";
        try 
            JSONParser parser = new JSONParser();
            Object jsonObj = parser.parse(json_string);
            JSONObject matchesobj = (JSONObject) jsonObj;

            if (matchesobj.containsKey("body")) 
                body = (String) matchesobj.get("body");
             else 
                JSONObject error = new JSONObject();
                error.put("error", "No body with Base64 data in Request.");
                System.out.println(error.toJSONString());
                return error;
            

         catch (ParseException ex) 
            ex.printStackTrace();
        

        byte[] decodedBytes = Base64.getDecoder().decode(body);
        String decodedString = new String(decodedBytes);
        // System.out.println(decodedString);

        JSONObject json = generateJson .getJson(decodedString, "", 2);

        JSONObject returnObject = new JSONObject();
        JSONObject headers = new JSONObject();
        returnObject.put("statusCode", 205);
        returnObject.put("isBase64Encoded", true);
        // returnObject.put("Content-Encoding", "gzip");

        returnObject.put("headers", headers);
        returnObject.put("body", compressStringAndReturnBase64(json.toString()));

        return (returnObject);
    

    public static String compressStringAndReturnBase64(String srcTxt) 

        ByteArrayOutputStream rstBao = new ByteArrayOutputStream();
        GZIPOutputStream zos;
        try 
            zos = new GZIPOutputStream(rstBao);
            zos.write(srcTxt.getBytes());
            IOUtils.closeQuietly(zos);
            byte[] bytes = rstBao.toByteArray();
            String base64comp = Base64.getEncoder().encodeToString(bytes);
            System.out.println("Json String is " + srcTxt.toString().getBytes().length + " compressed " + bytes.length + " compressed Base64 " + base64comp.getBytes().length);

            return base64comp;
         catch (IOException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return "";
    

我检查了 Base64 输出,它似乎工作正常(将其粘贴在 https://www.base64decode.org/ 中)。此外,当我与 Postman 核对时,如果我将响应保存到以 .gz 结尾的内容,我会得到一个可以用 7-zip 解压缩的二进制 blob。

在设置下,API Gateway Binary Media Types 已设置为 / 但我想让客户“看到”它是 GZIPped 并即时解码。但是,当我添加行时

returnObject.put("Content-Encoding", "gzip");

我收到 "message": "Internal server error" 并在 AWS API 日志中:由于配置错误,执行失败:格式错误的 Lambda 代理响应

Lambda 日志很好,所以它确实执行成功了,只是无法返回。

我认为我需要在 API 网关方面进行更多调整,有什么想法吗?

【问题讨论】:

你能展示全班吗?我在看public class XXXX implements ........你在实现什么接口? Content-Encoding 属于headers,而不是returnObject 中的***键。看来您将其放在错误的位置是在构建格式不正确的响应。 迈克尔,你的评论成功了!但我不能将其标记为答案? 【参考方案1】:

这听起来好像 API 网关上的二进制支持设置没有正确配置; API 网关正在尝试解析来自您的 lambda 的响应,而不是直接将其传递给客户端。

您可以在控制台中更新此设置:

【讨论】:

感谢您的评论。我已经启用了这个选项,但我看到在我原来的问题中,句子已被重命名。为了清楚起见,我通过设置星/星(不带空格)启用了这个二进制媒体类型选项。【参考方案2】:

在您的 HTTP 请求中添加带有有效负载内容类型的“Accept”标头。

接受:application/gzip

同样在 HTTP 响应中,应该有“Content-Type”标头指示响应内容类型。

内容类型:application/gzip

您的 lambda 会将 Base64 编码的二进制数据返回给 API Gateway。因此,为了解码数据,您的 HTTP 请求的 Accept 标头和 Response 的 Content-type 标头应该在那里。

【讨论】:

以上是关于AWS Java Lambda 压缩 JSON 响应失败:“由于配置错误,执行失败:格式错误的 Lambda 代理响应”的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JAVA 调用 AWS lambda 函数?

通过带有响应的 AWS Lambda 上传和处理文件

配置Java AWS Lambda使用的Objectmapper

如何为AWS Lambda创建和压缩docker容器

在AWS lambda函数上使用pyspark二进制文件,在向驱动程序发送其端口号之前退出错误Java网关进程

AWS Lambda 错误:解压缩后的大小必须小于 262144000 字节