JavaFX WebView / WebEngine Cache external JavaScri

2020-06-22 15:47发布

Situation: I have a Simple HTML page which have a normal script tag like this

<script src="main.js"></script>

After i load the html , i update the main.js , and make a reload (throught UI Button).

The Problem My new JS is not taken , i must close the Application and open it again.

What i did try: -not using webEngine.reload() , but webEngine.load() -making a new broswer every time a reload occurs. -making a new stage with a new broswer -setting all nodes caching off -in HTML following code

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

-InetAddressCachePolicy:

InetAddressCachePolicy.setNegativeIfNotSet(InetAddressCachePolicy.NEVER);

-VM Options: -Dnetworkaddress.cache.ttl=0.

The Question Is there any way to delete the cache or enforce the WebView to reload all resources other than appending a number to JS filename every time i update it?

Note:I use NetBeans 7.3 With last Java (update 22)

6条回答
等我变得足够好
2楼-- · 2020-06-22 15:58

How i worked around that:

  • Copy target directory containing HTML file and all JS files to a random generated Folder.
  • on Each reload generate a new folder , copy the contents , delete the old folder , load from the new folder.

The answer from "mcdonasm" was one of the things i tried , it would work if in "main.js" is only JavaScript , but if it referencing other JS files (as my case) the others will be cached.

查看更多
Melony?
3楼-- · 2020-06-22 15:59

I had a similar requirement but wanted a fixed directory location. This worked for me:

first = true;
final WebView view = new WebView();
view.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {

    @Override
    public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State t1) {
        System.out.println(t1);
        if(t1.equals(State.SUCCEEDED) && first) {
            first = false;
            view.getEngine().reload();
        }
    }
});

Basically force a reload once, and it will refresh the external data too.

查看更多
叛逆
4楼-- · 2020-06-22 16:06

I've had a similar problem, but with stylesheets. I am working on a web-authoring tool, and would like to reflect stylesheet changes in the displayed HTML files without restarting the application.

The only thing I've found that works is to create a new WebView object (that is never displayed) and to load the stylesheet explicitly in that. Once that's done, refreshing any html file that references that stylesheet will automatically reflect the change(s).

/** Forces an update to the internally-cached stylesheet.
 * @param file The CSS file.
 */
private void updateInternalCache(File file) {
    WebView cssLoader = new WebView();
    String fileLocation = file.toURI().toString();
    cssLoader.getEngine().load(fileLocation);
}
查看更多
Lonely孤独者°
5楼-- · 2020-06-22 16:10

After hours I found a quite convenient way I'd like to share:

webEngine.setJavaScriptEnabled(true);
webEngine.executeScript("location.reload(true);");

Apparently the JavaScript engine of JavaFX WebView fully supports the JavaScript method location.reload(true). The "true" forces a reload of resources from the server (or local file system). I tried it with and . If I change the content of the files and execute the above js code inside the WebEngine, the image gets replaced and the js-code executes as changed in bar.js.

Unfortunately there is no Java method to conveniently access this feature.

I admit, it doesn't really clear the cache, but it reloads the sources, which should be sufficient for most cases.

Tested in JRE 1.8.0_91

查看更多
你好瞎i
6楼-- · 2020-06-22 16:22

as described here: http://docs.oracle.com/javafx/8/webview/overview.htm

When working with the WebView component, you should remember that it has the default in-memory cache. It means that any cached content is lost once the application containing the WebView component is closed.

So, if we change "on-the-fly" a script or a css file inside a Webview, this file will not be reloaded/refreshed :-(
I've found another workaround, different (and it seems more simple) from that found from @Rany. I'll explain it hoping it can help someone...

Simply add at the end of the call to the script or stylesheet a custom parameter.
For example, instead to write this:

<script type="text/javascript" src="javascript.js"></script>

write this:

<script type="text/javascript" src="javascript.js?c=r_963"></script>

where "r_963" is a "r_" string followed by a random 0-999 int number. The final number must change its value everytime we need a refresh.
The same for stylesheet.
It works for me :-)

查看更多
欢心
7楼-- · 2020-06-22 16:25

I had a similar issue when I was working with user edited css files. The goal of the UI was to allow the user to edit the external .css files loaded from a given external .html file and see the changes in real-time in the WebEngine.

I was also unable to find any reference to a cache to clear or any way to force the WebEngine to re-load all its resources. But I did come up with what turned out to be a well performing solution.

What I ended up doing was load the contents of the external html file into memory and replace the < link > tags that refer to the associated external .css files, with < style > in-line css tags which contain the contents of the .css files. I then used

WebEngine.loadContent(EditedHTML); 

passing the newly editedHTML. This technique could easily be altered to load external JS files into in-line < Script > tags.

This technique worked very well for me because all of the files I am loading and editing are local. I load their contents into memory and save references to them on application start up. If you are trying to add JS files to a webPage retrieved from a server http request it may be a but more difficult to include this technique into your application, though I don't think it would be impossible.

The specific implementation would be dependent on the overall structure of your application but the sudo code would be something like this:

  1. Load html file's contents.
  2. Parse contents into HTML Document.*
  3. For each css < link > tag
    1. Load associated css file's contents
    2. Replace link tag with < style > tag who's contents are the loaded css file's contents
  4. Call WebEngine.loadContent(editedHTML)

*For parsing contents into an HTML Document, there are many useful and easy to use libraries that could be utilized. This SO Question is a good place to look for some of the most used. I use jSoup and find it to be very simple, powerful, and effective and would recommend you at least look/try it out before choosing to go with a different one.

This may require some re-structuring of your application, but this technique was by far the best solution I came up with. Let me know if you have any questions/concerns and I will try to answer/address them from my experience with this technique.

查看更多
登录 后发表回答