【问题标题】:Errors in reading text file from S3 via AWS Java SDK通过 AWS Java SDK 从 S3 读取文本文件时出错
【发布时间】:2021-03-05 18:23:05
【问题描述】:

我正在尝试通过 JAVA SDK v2 从 AWS S3 读取文本文件并通过 HTTP 将其发送回客户端(使用 com.sun.net.httpserver.HttpServer)。我想将内容作为字符串读取。但是我下面的简单代码不起作用。

有什么问题?如何解决?

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
//...
Region region = Region.US_WEST_2;
String bucketName = "file-store";

S3Client s3Client = S3Client.builder().region(region).build();
//...
class GetFileHandlerV2 implements HttpHandler {
@Override
public void handle(HttpExchange he) throws IOException {
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                                         .bucket(bucketName)
                                         .key(id + "/files/" + id + ".txt")
                                         .build();
OutputStream os = he.getResponseBody();
s3Client.getObject(getObjectRequest, ResponseTransformer.toOutputStream(os));
os.close();
//...
}
}

以下是错误:

java.io.IOException: response headers not sent yet
        at sun.net.httpserver.PlaceholderOutputStream.checkWrap(ExchangeImpl.java:433) ~[jdk.httpserver:?]
        at sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:448) ~[jdk.httpserver:?]
        at java.io.InputStream.transferTo(InputStream.java:772) ~[?:?]
        at comcast.labs.objectstore.FileRetriever$GetFileHandlerV2.handle(FileRetriever.java:112) [FileRetriever-1.0.jar:?]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) [jdk.httpserver:?]
        at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:82) [jdk.httpserver:?]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80) [jdk.httpserver:?]
        at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:692) [jdk.httpserver:?]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) [jdk.httpserver:?]
        at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:664) [jdk.httpserver:?]
        at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:159) [jdk.httpserver:?]
        at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:442) [jdk.httpserver:?]
        at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:408) [jdk.httpserver:?]
        at java.lang.Thread.run(Thread.java:835) [?:?]

【问题讨论】:

  • 没有。怎样才能全部读成String,然后自己处理HTTP响应?

标签: java amazon-web-services amazon-s3 aws-java-sdk-2.x com.sun.net.httpserver


【解决方案1】:

请考虑查看HttpExchange documentation。它提供了HttpExchange 生命周期中的典型步骤顺序。

具体来说,它表示在写入响应正文之前,使用getResponseBody返回的OutputStream,必须调用方法sendResponseHeaders才能真正开始向客户端发送信息。来自javadoc

开始使用当前的一组响应标头和此方法中指定的数字响应代码将响应发送回客户端....

请按照您的示例尝试以下操作:

@Override
public void handle(HttpExchange he) throws IOException {
  GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                                         .bucket(bucketName)
                                         .key(id + "/files/" + id + ".txt")
                                         .build();

  // Optional, and according to your file extension
  he.getResponseHeaders().set("Content-type", "text/plain");

  // Set the `responseLength` to zero, from the docs: chunked transfer encoding
  // will be used and an arbitrary amount of data may be sent.
  he.sendResponseHeaders(200, 0);

  // The rest of your code
  OutputStream os = he.getResponseBody();
  s3Client.getObject(getObjectRequest, ResponseTransformer.toOutputStream(os));
  os.close();
  //...
}

您可以先读取S3Client 返回的全部信息,然后也将其包装在您的处理程序中:

@Override
public void handle(HttpExchange he) throws IOException {
  // Fist, download actual object from S3 in the way you consider appropriate
  // This fragment of code could be refactored and be defined in its own
  // class/method
  GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                                         .bucket(bucketName)
                                         .key(id + "/files/" + id + ".txt")
                                         .build();
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  s3Client.getObject(getObjectRequest, ResponseTransformer.toOutputStream(bos));
  
  byte[] bytes = bos.toByteArray();

  // Perform the actual exchange

  // Optional, and according to your file extension
  he.getResponseHeaders().set("Content-type", "text/plain");

  he.sendResponseHeaders(200, bytes.length);
  // Please, perform the optimizations (buffering, etcetera) that you
  // consider necessary when writing the information to the user
  he.getResponseBody().write(bytes);
  he.close();
}

第二种方法允许您在需要时重构代码,将与 S3 交互相关的逻辑与与 HTTP 包装代码相关的逻辑区分开来。

【讨论】:

  • 嗨@TinaJ。您是否能够测试任何建议的解决方案?
猜你喜欢
  • 2017-11-07
  • 2018-10-18
  • 1970-01-01
  • 2018-08-11
  • 1970-01-01
  • 2021-09-28
  • 2022-01-20
  • 2019-10-15
  • 2020-05-07
相关资源
最近更新 更多