具有缓存功能的HTTP代理Servlet

时间:2019-05-14 10:31:04

标签: java servlets proxy inputstream httpentity

我正在通过参考this one来编写一个非常简单的代理servlet。我想要o添加缓存功能,其中缓存中的键将是URI。

当然,问题在于我无法缓存整个响应,因为如果我将其传递通过管道,则输入流将被消耗,然后缓存的响应将不再可用。

您认为解决此问题的最佳方法是什么?如何在不消耗HTTPResponse内容的情况下复制HTTPResponse(或仅HTTPEntity)?

1 个答案:

答案 0 :(得分:1)

除非另有说明,否则InputStream是单次拍摄:您只需消费一次即可。

如果您想多次阅读它,那就不再是流了,而是带有缓冲区的流。要缓存输入流,您应该将响应内容写入文件或内存中,以便可以再次(多次)重新读取。

HTTPEntity可以重新读取,但这取决于实现的类型。例如,您可以使用.isRepeatable()进行检查。这是apache的原始javadoc。

  

流式传输:内容是从流中接收的,或者是即时生成的。特别地,该类别包括从连接接收的实体。流式实体通常不可重复。
  自包含:内容位于内存中或通过独立于连接或其他实体的方式获得。独立的实体通常是可重复的。
  包装:内容是从另一个实体获得的。

您可以使用自包含FileEntity,因此可以重复使用(可重复读取)。

要将其存档(缓存到文件中),您可以读取HTTPEntity的内容并将其写入File。之后,您可以使用我们之前创建并编写的FileEntity创建一个File。最后,您只需要用新的HTTPResponse替换FileEntity的实体。

这是一个没有上下文的简单示例:

// Get the untouched entity from the HTTPResponse
HttpEntity originalEntity = response.getEntity();

// Obtain the content type of the response.
String contentType = originalEntity.getContentType().getElements()[0].getValue();

// Create a file for the cache. You should hash the the URL and pass it as the filename.
File targetFile = new File("/some/cache/folder/{--- HERE the URL in HASHED form ---}");

// Copy the input stream into the file above.
FileUtils.copyInputStreamToFile(originalEntity.getContent(), targetFile);

// Create a new Entity, pass the file and the replace the HTTPResponse's entity with it.
HttpEntity newEntity = new FileEntity(targetFile, ContentType.getByMimeType(contentType));
response.setEntity(newEntity);

现在,您以后可以一次又一次地重新读取文件中的内容。
您只需要根据URI查找文件即可:)

要缓存内存,可以使用ByteArrayEntity

此方法只是缓存正文。 不是http标头。

更新:替代

或者您可以使用 Apache HttpClient缓存
https://hc.apache.org/httpcomponents-client-ga/tutorial/html/caching.html