Как вернуть двоичные данные из AWS Lambda, написанные на Java

Учитывая, что теперь в Amazon Api Gateway можно обрабатывать двоичные данные и Amazon Lambda, я хотел попытаться создать конечную точку Amazon Lambda, которая возвращала электронную таблицу Excel. Это вполне возможно сделать с помощью node/js, как показано здесь. К сожалению, каждый раз, когда я пытаюсь сделать это с помощью Java, он разваливается.

Моя первоначальная попытка состояла в том, чтобы создать простую книгу с помощью apache XSSFWorkbook, записать ее в выходной поток, предоставленный RequestStreamHandler, и сделать это.

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileRequestHandler implements RequestStreamHandler {
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
            throws IOException {
        Workbook wb = new XSSFWorkbook();
        String sheetName = "Problem sheet";
        wb.createSheet(sheetName);
        wb.write(outputStream);
    }
}

При локальном тестировании выходной поток может быть передан в файл, в результате чего получается действительный выходной файл Excel.

import com.amazonaws.util.StringInputStream;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileRequestHandlerTest {

    @Test
    public void shouldCreateExcelFile() throws IOException {
        FileRequestHandler fileRequestHandler = new FileRequestHandler();
        InputStream inputStream = new StringInputStream("hello world");
        String fileName = "FileRequestLambda";
        String path = fileName + ".xlsx";
        FileOutputStream fileOutputStream = new FileOutputStream(path);

        fileRequestHandler.handleRequest(inputStream, fileOutputStream, TestUtils.createContext());
        fileOutputStream.close();
    }
}

Но когда я запускаю его в Amazon Lambda, я получаю искаженный двоичный вывод:

PKn��I_rels/.rels���j�0��}
�{㴃1F�^Ơ�2��l%1I,c�[��3�l
l�����H��4��R�l��·����q}*�2�������;�*��
t"�^�l;1W)�N�iD)ejuD�cKz[׷:}g����@:�
�3����4�7N�s_ni�G�M*7�����2R�+��    �2�/�����b��mC�Pp�ֱ$POyQ�抒�DsZ��IС�'un���~�PK����OPKn��I[Content_Types].xml�SMO1��+6��m��1���G%��β
�J[���MDL0�S;yo�{3i�Ӎ5�c��5lć�B'��nѰ��S}˪��)0�aÜg��`<�L��԰.�p'D�ZH�t��>Z�Tƅ ��@q=��]F��\4�=`+���P�!-!S.�v�@��+�����N�tEV=nHe7���S,;K]_h7Q+�W8߶Z��re��c�U�����}�����g�&A��,���H�$�B<��`�"�Jb���"���I�N�1���A���CI�#��܂v��?|\�{��`�b������$�c�D��|2�PKKB�>'PKn��IdocProps/app.xmlM��
�0D�~EȽ��ADҔ���A? ��6�lB�J?ߜ���0���ͯ��)�@��׍H6���V>��$;�SC
;̢(�ra�g�l�&�e��L!y�%��49��`_���4G���F��J��Wg
�GS�b����
~�PK�|wؑ�PKn��IdocProps/core.xmlm��J�0F��!�m�V����(���Ż��m��!�v}{ӺVP/g��a��wG5�wp~4��4�1-�u���n��c�גOFC����6��e�888c��<�홰
B��/P�g��q�b��!��'��W�)��"
�<p�S��I)Ŧ�onZR�@��Ќ�6�S�߅u��G?n�<��\�\����ۛ���t���p|��f� Q4��ac&ߓ��������i��"�UG+vV��z�ɯ���U�^�H@�����IM�$�&�PK����PKn��Ixl/sharedStrings.xml=�A� ツ��.z0Ɣ�`������,�����q2��o�ԇ���N�E��x5�z>�W���(R�K���^4{�����ŀ�5��y�V����y�m�XV�\�.��j�����
8�PKp��&x�PKn��I
xl/styles.xml���n� ��>bop2TQ��P)U��RWb�6*�����ӤS�Nw�s���3ߍ֐���t��(l��������ҝx�!N=@$ɀ��}��3c���ʰr`:i��2��w,�
�d
�T��R#�voc �;c�iE���Û��E<|��4Iɣ�����F#��n���B�z�F���y�j3y��yҥ�jt>���2��Lژ�!6��2F��OY��4@M�!���G��������1�t��y��p��" n����u�����a�ΦDi�9�&#��%I��9��}���cK��T��$?������`J������7���o��f��M|PK�1X@C�PKn��Ixl/workbook.xml���N�0��<��wj�E�8��J��P�;�����hmZ'Q�#����~;���;vCJ6   �Fà���"��|x|�}���#]����C�0�<֜'=�WiG��#y���O#�2i@������+`!��F�{��-�O�!/B�r)�;&h�����zOz�o����xO��I2����YuĔ��s�u��<J8Q�z6��Qm�:�,�c��Z�����PK1����dPKn��Ixl/_rels/workbook.xml.rels��Mk1@���0�nv-�R�^����0$����$dƯo���R�OC�ރ�-��������@Sՠ(�����ܼ?��b��p�����d�AJ�¾O�
#�/�޴f�iD�b�P6m�#Jy�N'�[�HO��E�k����3�W���ܑ`���Zri㪐����?�ض��e�������7p�wj�W5r���]������=�|���<:�[p��7�O�PK��4��9PKn��Ixl/worksheets/sheet1.xmleP�N�0���މ�V��THU$���$��j���[��c�����3��-v�nT���/a����7�Zߗ��z���]uQ���0 ��zJD�[�C3�3!�    }|鈝�H��ab4�br�^���v�z���:�)P1v%ܭ@W�"|�8�?X�ܚ���C[B�'�~��ȅO������Tyb�bgN�<�|��$��ƙ��{#&����h��>��D�Ű�z�#��6��8�LF�dQ����,4�xS����/PK�_�Y�lPKn��I����O_rels/.relsPKn��IKB�>'[Content_Types].xmlPKn��I�|wؑ��docProps/app.xmlPKn��I����mdocProps/core.xmlPKn��Ip��&x��xl/sharedStrings.xmlPKn��I�1X@C�
nxl/styles.xmlPKn��I1����d�xl/workbook.xmlPKn��I��4��9xl/_rels/workbook.xml.relsPKn��I�_�Y�l$   xl/worksheets/sheet1.xmlPK      ?Z

Выходные данные имеют размер около 5 КБ, в то время как выходные данные на моем локальном компьютере имеют размер около 3 КБ. Похоже, это проблема с двоичным выводом в целом для Java на Amazon Lambda. Когда я запускаю некоторый код, который записывает изображение в выходную строку, он также работает локально, но в результате получается изображение в два раза больше и искажено при запуске из Amazon Lambda.

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;

import java.io.*;
import java.net.URL;

public class ImageRequestHandler implements RequestStreamHandler {
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
            throws IOException {
        String address = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1d/AmazonWebservices_Logo.svg/580px-AmazonWebservices_Logo.svg.png";
        URL url = new URL(address);

        InputStream in = new BufferedInputStream(url.openStream());
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int n;
        while (-1!=(n=in.read(buf)))
        {
            out.write(buf, 0, n);
        }
        out.close();
        in.close();
        byte[] response = out.toByteArray();
        outputStream.write(response);
    }
}

Типы входных и выходных потоков:

lambdainternal.util.NativeMemoryAsInputStream lambdainternal.util.LambdaByteArrayOutputStream

Помощь?


person user1853665    schedule 16.12.2016    source источник
comment
Подумайте, действительно ли вы хотите протолкнуть весь файл Excel через результат вашей лямбды. Может быть, имеет смысл разместить его на s3 и вернуть предварительно подписанный URL-адрес? Это будет обрабатывать файлы Excel любого размера - полезная нагрузка лямбда-ответа, по-видимому, может быть только 6M Это также сократит выполнение ваших лямбда-выражений (запись в S3 будет довольно надежной и очень быстрой) и оставит передачу данных в руки S3, который очень хорош в этом. Вы также можете загрузить файл снова в случае сбоя без повторного вызова.   -  person Daniel Farrell    schedule 16.12.2016


Ответы (1)


У меня была такая же проблема с возвратом изображения JPG из Amazon Lambda, и я нашел обходной путь. Вам нужно закодировать выходной поток с кодировкой base64:

OutputStream encodedStream = Base64.getEncoder().wrap(outputStream);
encodedStream.write(response);
encodedStream.close();

Затем вам необходимо обновить ответ метода и ответ интеграции вашей функции, как описано здесь: 41434295">API AWS Gateway base64Decode создает искаженный двоичный файл?

person Hans    schedule 15.05.2017