Java Webstart和URLConnection缓存API

27

URLConnection缓存API的描述中最后一句话是:

  

在Java 2标准版中没有默认的实现方式来进行URLConnection缓存。但是,Java插件和Java WebStart提供了一个开箱即用的实现。

我在哪里可以找到有关Webstart ResponseCache的更多信息?

  • 哪些平台上的Webstart版本激活了缓存?
  • 在哪些情况下它是活跃的?只有HTTP Get吗?
  • 它可以进行配置吗?
  • 源代码是否可用?

背景:

案例1

使用以下(Groovy)代码

def url = new URL('http://repo1.maven.org/maven2/')
def connection = url.openConnection()
def result = connection.inputStream.text

我期望每次执行代码时都会联系服务器。但是当在

Java Web Start 10.9.2.05
JRE-Version verwenden 1.7.0_09-b05 Java HotSpot(TM) Client VM

行为不同。第一次执行代码时,会联系服务器。所有后续的代码执行都不涉及任何与服务器的通信(使用wireshark进行跟踪)。

但情况变得更加奇怪了。在重新启动webstart应用程序之后,第一次执行代码时,会请求url http://repo1.maven.org/maven2/.pack.gz,导致404错误。只有这之后才会请求原始的url,并返回304 NOT MODIFIED。所有后续的执行都不涉及任何与服务器的通信。

我认为透明地增强URLConnection的缓存功能的方法很好,可以帮助提高客户端应用程序的性能。但由于服务器在这种情况下没有定义Expires头也没有定义cache-control头,因此我认为上面的代码应该总是向服务器发出请求而不是默默地忽略我的请求。

案例二

以下代码在使用webstart 10.1.1.255时无法工作(这是某个早期的java 7 beta版本安装的,但我不知道是哪个版本)。

URL url = new URL("http://repo1.maven.org/maven2/");
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept-Encoding", "gzip");
connection.connect();
InputStream is = connection.getInputStream();
if ("gzip".equalsIgnoreCase(connection.getContentEncoding()))
{
    is = new GZIPInputStream(is);
}
is.close();

使用Java Web Start 10.1.1.255,从第二次开始执行时我遇到了一个

java.io.IOException: Not in GZIP format
    at java.util.zip.GZIPInputStream.readHeader(Unknown Source)
    at java.util.zip.GZIPInputStream.<init>(Unknown Source)
    at java.util.zip.GZIPInputStream.<init>(Unknown Source)

使用Java Web Start 1.6.0_24Java Web Start 10.2.1.255都无法重现问题。

通过Wireshark,我发现当出现错误时,http头包含一个If-Modified-Since条目,因此返回代码为304。在其他情况下没有If-Modified-Since。因此,我认为缓存未在webstart的稳定版本中激活,尽管上面链接的最后一句话说了这个。

似乎测试版的缓存对http get请求进行了积极调整:它使用了If-Modified-Since并自动尝试使用gzip编码——即使客户端代码没有设置此标头。但是当缓存命中时,返回的流不会被gzip压缩,尽管getContentEncoding返回“gzip”。

由于缓存似乎未在我的机器上的webstart稳定版本中激活,因此我无法验证bug是否存在,因此犹豫要提交bug报告。


我已经进行了调查,但是并不明显如何获取Java WebStart源代码部分。我的第一个猜测是缓存实现中存在某种错误。 - Yves Martin
1
尝试使用Apache HttpComponents - Pablo Moretti
我下载了JDK7的源代码,里面甚至没有包括Java Web Start的公共API类(例如javax.jnlp.BasicService),更别提私有实现类了,而这些是我期望找到相关代码的地方。看起来Oracle并没有发布javaws的源代码? - Mike Clark
你试过注释掉设置接受编码为GZIP的那一行吗? connection.setRequestProperty("Accept-Encoding", "gzip"); - Ahmed Hashem
3个回答

3
到目前为止我找到的唯一信息在JDK 7中的Java Rich Internet应用增强功能
默认启用缓存:现在默认启用Web Start模式下运行的应用程序代码的网络内容缓存。这使得应用程序具有改进的性能,并且与小程序执行模式一致。为了确保使用最新的内容副本,应用程序可以使用URLConnection.setUseCaches(false)或请求标头Cache-Control值no-cache/no-store。
处理gzip编码内容的改进: 部署缓存将以压缩形式保留应用程序内容并将其作为带有gzip内容编码的HTTP标头返回给应用程序。这使得行为在不同的执行模式(首次启动与随后启动、启用缓存与禁用缓存)之间更加一致。有关更多详细信息,请参见6575586

虽然这并没有回答我所有的问题,但现在我会接受我的自己的答案。 - Tobias Schulte

0

我修改了你的代码。希望它对你有用。

URL url = new URL("http://repo1.maven.org/maven2/");
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept-Encoding", "ISO-8859-1");
connection.connect();
InputStream is = connection.getInputStream();
if ("gzip".equalsIgnoreCase(connection.getContentEncoding()))
{
    is = new GZIPInputStream(is);
}
is.close();

0

缓存似乎是由com.sun.deploy.cache.DeployCacheHandler实现的,它位于deploy.jar中。我在任何官方仓库中都找不到源代码;那个链接是某种灰色市场副本。

我一时看不出它是否在任何特定平台上被禁用(或启用!)。自Java 6以来,该缓存处理程序就一直存在。

它只缓存GET请求。在isResourceCacheable方法中的注释解释了这一点:

    // do not cache resource if:
    // 1. cache disabled
    // 2. useCaches is set to false and resource is non jar/zip file
    // 3. connection is not a GET request
    // 4. cache-control header is set to no-store
    // 5. lastModified and expiration not set
    // 6. resource is a partial body resource

我没有看到任何直接配置缓存的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接