使用Java在AWS Lambda上解析multipart/form-data Body

Arm*_*nto 6 java multipartform-data aws-lambda

我是AWS Lambda的新手,我正在尝试实现一个Lambda函数,该函数接收包含编码为multipart/form-data的数据的POST请求.使用Lambda代理集成通过API网关接收消息,并且当主体到达Lambda函数时,主体在Base64中进行编码.手动解码后,我看到它包含如下所示的多部分体:

-----WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="param1"

value1
-----WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="param2"

value2
------WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="myfile"; filename="ivr.png"
Content-Type: image/png

PNG
... [binary stuff]
------WebKitFormBoundary3EZ0C3tbP2JpAmz4--
Run Code Online (Sandbox Code Playgroud)

我需要的是在java 8中解析此消息,以便我可以访问各个部分.我设法使用+ javax.mail.Multipart +对象,但似乎我无法访问部件的"name"属性,因此我无法区分相同的类型元素,例如"param1"和"param2".我相信这可能与此类用于解析电子邮件的事实有关...是否有另一种方法来解析lambda函数内的这个多部分主体?这是我必须解析的代码(base64是包含正文的字符串):

DataSource source = new ByteArrayDataSource(new ByteArrayInputStream(Base64.decodeBase64(base64)), "multipart/mixed");
MimeMultipart mp = new MimeMultipart(source);
Run Code Online (Sandbox Code Playgroud)

我很感激你能提供的任何帮助.

ᴛʜᴇ*_*ᴛᴇʟ 2

好吧,这绝对不是理想的解决方案,但我能够做到这一点。

问题

实际上有很多库可以解析多部分表单数据。实际的问题是所有库都依赖于javax.servlet包 - 最重要的HttpServletRequest是类(还有其他一些)。

由于我们无法javax.servlet在 AWS Lambda 环境中访问包类,因此我的解决方案是修复该问题。


解决方案

  1. javax.servlet 从 GitHub下载该包并将其添加到您的 lambda 函数中。请参见下图 - 您可以看到我的类MultipartFormDataTest位于我的包中com...,并且我javax.servlet在同一个 Java 模块中也有包。

Javax Servlet 包添加到 Lambda 模块

  1. 一旦我们这样做了,我们就可以使用一个或多个库来为我们完成所有工作。我发现可以解析文件内容的最好的库是 Delight FileUpload - https://mvnrepository.com/artifact/org.javadelight/delight-fileupload

  2. 添加该库后,下面的方法getFilesFromMultipartFormData()将返回ArrayList<File>列表中的每个项目代表File请求中发送的项目。

/**
 * @param context context
 * @param body this value taken from the `request.getBody()`
 * @param contentType this value is taken from `request.headers().get("Content-Type")`
 * @return List of File objects
 */
private List<File> getFilesFromMultipartFormData(Context context, String body, String contentType) {
    ArrayList<File> files = new ArrayList<>();
    List<FileItem> fileItems = FileUpload.parse(body.getBytes(StandardCharsets.UTF_8), contentType);

    for(FileItem fileItem : fileItems) {
        if(fileItem == null) {
            continue;
        }

        logger.log("fileItem name: " + fileItem.getName());
        logger.log("fileItem content-type: " + fileItem.getContentType());
        logger.log("fileItem size: " + fileItem.getSize());

        // Note: instead of storing it locally, you can also directly store it to S3 for example
        try {
            // I'm setting the extension to .png but you can look at the fileItem.getContentType()
            // to make sure it is an image vs. pdf vs. some other format
            File temp = File.createTempFile(fileItem.getName(), ".png");
            Files.copy(fileItem.getInputStream(), temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
            files.add(temp);
        } catch (Exception e) {
            continue;
        }
    }

    return files;
}
Run Code Online (Sandbox Code Playgroud)