【问题标题】:AWS Lambda and S3 - uploaded pdf file is blank/corruptAWS Lambda 和 S3 - 上传的 pdf 文件为空白/损坏
【发布时间】:2020-06-05 06:34:25
【问题描述】:

我有一个 Spring 应用程序(在 AWS Lambda 上运行),它获取一个文件并将其上传到 AWS S3。

Spring 控制器将 MultipartFile 发送到我的方法,然后使用 Amazon API Gateway 将其上传到 AWS S3。

public static void uploadFile(MultipartFile mpFile, String fileName) throws IOException{

    String dirPath = System.getProperty("java.io.tmpdir", "/tmp");
    File file = new File(dirPath  + "/" + fileName);

    OutputStream ops = new FileOutputStream(file);
    ops.write(mpFile.getBytes());

    s3client.putObject("fakebucketname", fileName, file);

}

我尝试上传包含 2 页文本的 PDF 文件。上传后,PDF 文件(在 AWS S3 上)有 2 个空白页。

为什么上传的PDF文件是空白的?

我也尝试过使用其他文件(如 PNG 图像),当我打开它时,我上传的图像已损坏。

唯一有效的是我上传了一个文本文件。

【问题讨论】:

  • 为什么在尝试将文件上传到 S3 之前不关闭输出流?
  • 请参阅答案中的替代方案,以获得使用 S3 上传的更好方法。直接上传到 S3 是安全的,并且会大大提高上传时间的性能。

标签: java spring amazon-web-services amazon-s3 aws-lambda


【解决方案1】:

事实证明,这可以做到这一点。感谢@KunLun 的帮助,这一切都与编码有关。在我的场景中,文件是通过 POST 到 url 传递给 aws 的多部分文件 (pdf)。

        Base64.Encoder enc = Base64.getEncoder();
        byte[] encbytes = enc.encode(file.getBytes());
        for (int i = 0; i < encbytes.length; i++)
        {
            System.out.printf("%c", (char) encbytes[i]);
            if (i != 0 && i % 4 == 0)
                System.out.print(' ');
        }
        Base64.Decoder dec = Base64.getDecoder();
        byte[] barray2 = dec.decode(encbytes);
        InputStream fis = new ByteArrayInputStream(barray2);

        PutObjectResult objectResult = s3client.putObject("xxx", file.getOriginalFilename(), fis, data);

【讨论】:

    【解决方案2】:

    我可以说我见过人们这样做,他们的应用程序接受 MultipartFile,并将其代理上传到 S3。

    上传到您的应用程序,然后诚实地上传到 S3 是错误的方法,并且有许多缺点,首先否定了使用 S3 的好处。只需生成一个预签名的 URL,然后让您的用户直接上传到 S3。出于以下几个原因,这是更可取的,但主要的原因是:

    • 如果不小心,一个接受 MultipartFile 上传的应用很容易被 DDOS 攻击,当有人同时上传许多文件时,我们的应用就发生了这种情况,整个系统出现故障。
    • 上传到后端应用然后再上传到 S3 会慢很多。

    如果您碰巧使用 Cognito,您也可以使用 AWS Amplify 使用 0 后端代码来实现此目的。我强烈推荐,但如果没有,那么预签名的 URL 就是要走的路。

    【讨论】:

    • 生成一个预签名的 url 到底是什么意思?如果我们使用 Java spring 应用程序,我们的客户端将需要在某种 api url 上发布 pdf 表单,您是在谈论类似的实现吗?请详细说明您在此处考虑的工作流程:客户必须在某处发布 pdf 表单,然后对其进行操作,然后需要使用 spring 通过重定向显示新的操作表单
    • 基本上你可以告诉S3,嘿给我一个临时URL来上传文件,然后把它交给用户上传。一旦他们上传了你就可以操作它。
    • 在应用程序中构建这似乎不是一个非常可行的选择。你能详细说明一下吗?是否可以为每个想要提交表单的客户重新创建这个临时 url?
    • 不确定在这种情况下可行是什么意思,但无论如何你正在做的是user -&gt; upload to app -&gt; upload to s3,但你可以先做app gives URL to user 然后user -&gt; upload to s3。我建议您至少在确定它不可行之前先尝试 AWS 方式,只需在某个地方找到一个教程,语言无关紧要,只需将概念记下来github.com/jkahn117/aws-presigned-url-upload
    • 这并没有告诉我们如何上传文件。告诉我们如何上传已写入输出流的字符串。您能否阐明如何使用类似的方法将整个 pdf 写入 s3?
    猜你喜欢
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-07
    • 2022-08-17
    • 2020-01-29
    • 2018-01-16
    • 2020-04-15
    • 2018-12-30
    相关资源
    最近更新 更多