Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java从S3存储桶读取文件,并以模拟实际文件上载的方式将HTTP PUT文件发送到另一个存储桶的预先签名的AWS S3 URL_Java_Amazon Web Services_File_File Io_Http Headers - Fatal编程技术网

使用Java从S3存储桶读取文件,并以模拟实际文件上载的方式将HTTP PUT文件发送到另一个存储桶的预先签名的AWS S3 URL

使用Java从S3存储桶读取文件,并以模拟实际文件上载的方式将HTTP PUT文件发送到另一个存储桶的预先签名的AWS S3 URL,java,amazon-web-services,file,file-io,http-headers,Java,Amazon Web Services,File,File Io,Http Headers,Java和HTTP请求的新特性 为什么这个问题不是重复的:我没有使用AWS SDK生成任何预先签名的URL。我从外部API获取它 以下是我试图实现的目标: 步骤1:读取文件的源S3存储桶(目前为.xlsx) 步骤2:通过将该文件转换为InputStreamReader来解析该文件(我需要这里的帮助) 步骤3:通过将InputStreamReader的内容传输到OutputStreamWriter,在我已经从外部团队获得的预签名S3URL上,对该文件执行HTTP PUT。文件必须位于目标S3存储桶

Java和HTTP请求的新特性

为什么这个问题不是重复的:我没有使用AWS SDK生成任何预先签名的URL。我从外部API获取它

以下是我试图实现的目标:

步骤1:读取文件的源S3存储桶(目前为
.xlsx

步骤2:通过将该文件转换为InputStreamReader来解析该文件(我需要这里的帮助)

步骤3:通过将InputStreamReader的内容传输到OutputStreamWriter,在我已经从外部团队获得的预签名S3URL上,对该文件执行HTTP PUT。文件必须位于目标S3存储桶中,就像通过拖放手动上载文件一样。(这里也需要帮助)

以下是我尝试过的:

步骤1:读取文件的S3存储桶

public class LambdaMain implements RequestHandler<S3Event, String>  {

    @Override
    public String handleRequest(final S3Event event, final Context context) {

        System.out.println("Create object was called on the S3 bucket");
        S3EventNotification.S3EventNotificationRecord record = event.getRecords().get(0);

        String srcBucket = record.getS3().getBucket().getName();
        String srcKey = record.getS3().getObject().getUrlDecodedKey();

        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                .withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
                .build();

        S3Object s3Object = s3Client.getObject(new GetObjectRequest(
                srcBucket, srcKey));

        String presignedS3Url = //Assume that I have this by making an external API call
        InputStreamReader inputStreamReader = parseFileFromS3(s3Object); #Step 2
        int responseCode = putContentIntoS3URL(inputStreamReader, presignedS3Url); #Step 3

}
步骤3:通过将内容从
InputStreamReader
复制到
OutputStreamWriter

    private InputStreamReader parseFileFromS3(S3Object s3Object) {
        return new InputStreamReader(s3Object.getObjectContent(), StandardCharsets.UTF_8);
    }
   private int putContentIntoS3URL(InputStreamReader inputStreamReader, String presignedS3Url) {
        URL url = null;
        try {
            url = new URL(presignedS3Url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        HttpURLConnection httpCon = null;

        try {
            assert url != null;
            httpCon = (HttpURLConnection) url.openConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        httpCon.setDoOutput(true);

        try {
            httpCon.setRequestMethod("PUT");

        } catch (ProtocolException e) {
            e.printStackTrace();
        }

        OutputStreamWriter outputStreamWriter = null;
        try {
            outputStreamWriter = new OutputStreamWriter(
                    httpCon.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            IOUtils.copy(inputStreamReader, outputStreamWriter); 
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            outputStreamWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            httpCon.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        int responseCode = 0;

        try {
            responseCode = httpCon.getResponseCode();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseCode;
    }
中间方法的问题是,当我通过S3 insert触发器读取
.xlsx
文件并将其放入URL时,当我下载上传的文件时,它会作为一些胡言乱语被下载

当我尝试读取
.png
文件并将其放入URL时,当我下载上传的文件时,它会被下载为带有一些胡言乱语的文本文件(不过我确实在其中看到了png这个词)

感觉我在以下方面犯了错误:

  • 错误地创建了
    OutputStreamWriter
    ,因为我不知道如何通过HTTP请求发送文件

  • 假设每个文件类型都可以以通用方式处理

  • 未在HTTP请求中设置
    内容类型

  • 希望S3在PUT操作后神奇地理解我的文件类型

  • 我想知道我的上述4个假设是否正确

    其目的是,我正确地放置文件数据,使其与正确的文件类型/扩展名一起位于S3存储桶中。我希望我的努力值得获得一些帮助。我已经对HTTP PUT和File/IO进行了大量搜索,但我无法将它们链接到我的用例中,因为我在执行文件I/O之后执行HTTP PUT

    更新1:

    我已经添加了
    setRequestProperty(“Content Type”,“application/vnd.openxmlformats officedocument.spreadsheetml.sheet”)
    ,但该文件不包含在具有文件扩展名的S3存储桶中。它只是作为一个对象放在那里

    更新2:

    我认为这也与
    setContentDisposition()
    头有关,尽管我不确定如何为Excel文件设置这些头

    更新3:

    这可能仅仅与预先签名的S3URL本身是如何出售给我们有关。正如问题中提到的,我说我们从其他团队获得了预先签名的S3URL。问题本身有多个部分需要回答

  • 默认的预签名S3URL是否允许客户端在HTTP头中设置
    内容类型
    内容处置
    :我在这里设置了另一个单独的问题,因为它非常不清楚:

  • 如果上述问题的答案是正确的,那么,也只有这样,我们才能进入如何设置文件内容并将其写入
    OutputStream


  • 您正在使用InputStreamReader和OutputStreamWriter,它们都是字节流和字符流之间的桥梁。但是,您将这些用于字节数据,这意味着您首先将字节转换为字符,然后再转换回字节。因为您的数据不是字符数据,所以这种转换可能解释了为什么您会因此变得胡言乱语

    我开始尝试摆脱读写器,而是直接使用InputStream(您已经从s3Object.getObjectContent()获得)和OutputStream(您从httpCon.getOutputStream()获得)。IOUtils.copy也应该支持这一点


    另外,在构造InputStreamReader时,您将StandardCharsets.UTF_8设置为要使用的字符集,但在构造OutputStreamWriter时,您不会设置字符集。如果默认字符集不是UTF-8,此转换可能还会导致乱码。

    为什么不使用AWS SDK for Java而不是较低级别的HTTP方法?请看,其他团队给我们预先指定的S3URL是一个很难满足的要求。因为它涉及很多安全认证,所以我们自己不这么做,而是让其他团队来处理预先签名的S3URL创建。有趣。看起来AWS文档中也有一些关于这方面的指导。(显然支持设置内容类型)。您可以尝试编写代码来上传到一个简单的web服务,该服务接受通过HTTP上传文件。一旦你开始工作,修改你的代码来使用S3。