我打算将结构化数据写入通过HTTP客户端访问的资源。用于执行此操作的API(对于JSON,YAML,XML)往往会让我将OutputStream
传递给他们 - 他们不会给我InputStream
。
无论好坏,Apache HTTP Components HttpClient是这里使用的客户端。 (我们使用的其他库依赖于它。在大多数情况下它并不完全是坏事,并且至少不会强迫我们使用奇怪的线程本地黑客只是为了获得理智的行为,与java.net.URL
不同。)
发出请求时,HttpEntityEnclosingRequestBase
(在HttpClient中)强制我设置HttpEntity
以获取服务器的任何数据。 HttpEntity
似乎迫使我实施getContent()
,并返回InputStream
。
我没有InputStream
,所以我不得不在两种解决方法之间做出选择:
A)将所有数据串行化为内存中的字节数组,然后将其全部重新流出。我不想这样做,因为通常,数据的序列化形式比数据本身占用更多的内存,在某些情况下我们甚至没有在内存中首先使用它,所以这样做要求麻烦。
B)创建Pipe
。旋转第二个线程将对象写入管道的OutputStream
端。返回InputStream
结尾。这实际上无法在HttpEntity
本身中完成,因为HttpEntity
不知道何时不再需要数据流。 (当你到达流的末尾时,它可以做出有根据的猜测,但是如果与服务器的连接中途丢失了一半,你就会永远打开管道。)这意味着我最终将解决方法移到了每一个建立连接的地方,这是很多结构性重复。
这两种解决方法都不是很好,但我猜(B)是“不那么糟糕”,因为当传输大对象时,它至少不会使整个应用程序崩溃。
据我所知:
public class WriteLogicEntity extends AbstractHttpEntity {
private final WriteLogic writeLogic;
public InputStreamEntity(WriteLogic writeLogic) {
this(instream, null);
}
public InputStreamEntity(WriteLogic writeLogic,
ContentType contentType) {
this.writeLogic = writeLogic;
if(contentType != null) {
this.setContentType(contentType.toString());
}
}
@Override
public boolean isRepeatable() {
// We could enforce that all WriteLogic be repeatable
// or add a similar method there, but at least for now,
// assuming it isn't repeatable is safe.
return false;
}
@Override
public long getContentLength() {
// We really don't know.
return -1L;
}
@Override
public InputStream getContent() throws IOException {
//TODO: What do we do here?
}
@Override
public void writeTo(OutputStream outstream) throws IOException {
writeLogic.withOutputStream(outstream);
}
@Override
public boolean isStreaming() {
return true; //TODO: Verify this choice
}
}
public interface WriteLogic {
void withOutputStream(OutputStream stream) throws IOException;
}
现在我想知道getContent()
是否可以抛出UnsupportedOperationException。当然,在提出请求时,无论如何他们都会使用writeTo()
,对吧?好吧,我无法弄明白。即使它在一个实验中有效,也不能保证某些请求不可能要求拨打getContent()
。
所以我想知道是否有人比我更了解这个库可以调用它 - 跳过实现这个方法是否安全?
(这个getContent()
方法似乎不应该在API中。或者它应该被记录到至少允许我实现它的某种方式。我打算提交一个关于它的bug,无论如何,因为当你试图写一个请求时被迫提供InputStream
是非常不方便的。)
答案 0 :(得分:1)
如果实体内容无法表示为InputStream getContent
方法,则抛出UnsupportedOperationException。内部HttpClient使用writeTo
将实体内容流式传输到底层HTTP连接。