Java Webstart and URLConnection caching API

2019-03-22 16:04发布

问题:

The description of the URLConnection caching API states as the last sentence:

There is no default implementation of URLConnection caching in the Java 2 Standard Edition. However, Java Plugin and Java WebStart do provide one out of the box.

Where can I find more information about the Webstart ResponseCache?

  • Which Versions of Webstart on which platforms activate Caching?
  • In which cases is it active? Only HTTP Get?
  • Can it be configured?
  • Is the sourcecode available?

Background:

Case 1

With following (groovy) code

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

I would expect that every time the code is executed the server is contacted. But when executed in

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

the behavior is different. The first time the code is executed, the server is contacted. All subsequent executions of the code don't involve any communication to the server (traced using wireshark).

But it gets even stranger. After re-start of the webstart app, the first time the code is executed, the url http://repo1.maven.org/maven2/.pack.gz is requested resulting in a 404. Only than the original url is requested resulting in a 304 NOT MODIFIED. All subsequent executions don't involve any communication to the server.

I think the approach of transparently enhancing the urlconnection with caching capabilities is nice and fine and helps improve performance of client applications. But since the server in this case didn't define an Expires header nor a cache-control header, I think the code above should always ask the server and not silently ignore my request.

Case 2

Following code does not work when executed with webstart 10.1.1.255 (this was installed by some early beta Version of java 7, but I don't know which one this was)

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();

With Java Web Start 10.1.1.255 starting with the second execution I got a

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)

With both Java Web Start 1.6.0_24 and now Java Web Start 10.2.1.255 I am not able to reproduce the problem.

With Wireshark I saw that in the case where I got the error, the http header contained an If-Modified-Since entry, and the return code therefore was 304. In the other cases there was no If-Modified-Since. Therefore I think that caching is not active in the stable versions of webstart -- despite the last sentence of the above link.

It seems, that the cache of the beta version does aggressive tuning to http get requests: It does use If-Modified-Since and automatically tries to use gzip encoding -- even if the client code does not set this header. But when the cache is hit, the returned stream is not gzipped, although getContentEncoding returns "gzip".

Since the caching seems not to be active in the stable version of webstart on my machine, I cannot verify if the bug is in the code any more and therefore hesitate to file a bug report.

回答1:

The only information I have found so far is at Java Rich Internet Applications Enhancements in JDK 7

Caching enabled by default: Caching of network content for application code running in Web Start mode is now enabled by default. This allows application improved performance and consistency with applet execution mode. To ensure the latest copy of content is used, the application can use URLConnection.setUseCaches(false) or request header Cache-Control values no-cache/no-store.

[...]

Improvements for handling content with gzip encoding: The deployment cache will keep application content in compressed form and return it to the application as-is with gzip content-encoding in the HTTP header. This makes behavior more consistent across different execution modes (first launch versus subsequent launch, cache enabled versus cache disabled). See 6575586 for more details.



回答2:

I modified your code. Hope it works for you.

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();


回答3:

The cache appears to be implemented by com.sun.deploy.cache.DeployCacheHandler, which lives in deploy.jar. I can't find the source in any official repositories; that link is to some sort of grey-market copy.

I can't, at a glance, find any indications that it is disabled (or enabled!) on any particular platforms. This cache handler has been present since at least Java 6.

It only caches GET requests. A comment in the isResourceCacheable method explains:

    // 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

I don't see any way to directly configure the cache.