Java Webstart and URLConnection caching API



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

Java 2 Standard Edition中没有URLConnection缓存的默认实现。然而,Java插件和Java WebStart确实提供了开箱即用的功能。

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

  • 哪些版本的Webstart在哪些平台上激活缓存
  • 在哪些情况下它是活动的?仅HTTP获取
  • 可以配置吗
  • 源代码可用吗

背景:

案例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。所有后续执行都不涉及与服务器的任何通信。

我认为通过缓存功能透明地增强urlronnection的方法很好,有助于提高客户端应用程序的性能。但是,由于本例中的服务器既没有定义Expires标头,也没有定义缓存控制标头,我认为上面的代码应该始终询问服务器,而不是默默地忽略我的请求。

案例2

以下代码在使用webstart 10.1.1.255执行时不起作用(这是由java7的早期测试版安装的,但我不知道这是哪一个)

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_24和现在的Java 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中似乎不活跃,我无法再验证代码中是否存在漏洞,因此在提交漏洞报告时犹豫不决。

到目前为止,我发现的唯一信息是JDK 7 中的Java Rich Internet Applications Enhancements

默认情况下启用缓存:现在默认情况下已启用在Web启动模式下运行的应用程序代码的网络内容缓存。这允许应用程序提高性能,并与小程序执行模式保持一致。为了确保使用内容的最新副本,应用程序可以使用URLConnection.setUseCaches(false)或请求标头Cache Control值no-Cache/no-store。

[…]

使用gzip编码处理内容的改进:部署缓存将保持应用程序内容的压缩形式,并将其返回给应用程序,就像在HTTP标头中使用gzip内容编码一样。这使得不同执行模式之间的行为更加一致(首次启动与后续启动、启用缓存与禁用缓存)。详见6575586。

我修改了您的代码。希望它对你有用。
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();

缓存似乎是由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

我看不出有任何方法可以直接配置缓存。

最新更新