java - 通过 AWS Java SDK 从 S3 读取文本文件时出错
问题描述
我试图通过 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) [?:?]
解决方案
请考虑查看HttpExchange
文档。它提供了HttpExchange
.
具体来说,它表示在写入响应正文之前,必须调用OutputStream
返回getResponseBody
的方法才能真正开始向客户端发送信息。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
first 返回的全部信息,然后将其包装在您的处理程序上:
@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 包装代码相关的逻辑区分开来。
推荐阅读
- javascript - 为什么下面的 react 功能组件不能正常工作?
- android - 断言失败:布尔表达式不能为空。最初调用加载屏幕
- ssl - 客户端发送许多“客户端问候”消息以发起 1 个请求
- django-rest-framework - 将 Validationerror 转换为 Django rest 框架中的 serializers.Validationerror
- node.js - 出现错误:找不到模块“mg-api-js”的声明文件
- python - Selenium 驱动程序不返回所有 Web 元素,即使它们是同一个类
- flutter - 在 Android 中拉起 ListView 时,ScrollController 侦听器不会触发
- python - 如何从 android studio 执行 python 文件?
- flutter - 为什么我的变量在 StatelessWidget 中成功更改,即使我收到警告
- html - NoReverseMatch at /update Reverse for 'update_profile' with arguments '('',)' not found. 尝试了 1 种模式:['updateprofile/(?P
[^/]+)$']