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

时间:2019-04-27 06:52:37

标签: aws-lambda aws-api-gateway

我正在从AWS API网关调用AWS Lambda函数。由于有时返回的JSON太大(主体大小太大等),因此需要压缩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结尾的内容,则会得到一个二进制blob,可以使用7-zip解压缩该二进制blob。

在设置下,API网关二进制媒体类型已设置为 / 但是我想让客户端“看到”它是GZIPped并即时对其进行解码。但是,当我添加行

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

我收到{“ message”:“内部服务器错误”},并在AWS API日志中:由于配置错误,执行失败:Lambda代理响应格式错误

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

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

2 个答案:

答案 0 :(得分:2)

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

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

API Gateway binary support

答案 1 :(得分:0)

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

  

接受:application / gzip

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

  

内容类型:application / gzip

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