perwendel / spark

A simple expressive web framework for java. Spark has a kotlin DSL https://github.com/perwendel/spark-kotlin
Apache License 2.0
9.64k stars 1.56k forks source link

How to stop index.html static file caching? #1052

Open JoaaoVerona opened 5 years ago

JoaaoVerona commented 5 years ago

I'm developing my backend with Spark, and the frontend with ReactJS. After compiling the frontend code, it generates a directory with all the content, where index.html is the starting point.

Then, I configure static files like this:

if (Skiley.production) {
    Spark.staticFiles.expireTime(7 * 24 * 60 * 60)
    Spark.staticFiles.externalLocation(Skiley.frontendDirectory.path)
    Spark.staticFiles.header("Content-Encoding", "gzip")
}

ReactJS, Webpack and friends generate all my project's code into .css and .js files with a hash suffix (a checksum), which changes everytime my code also changes, therefore I can cache these files for long enough (since, when there is a new version available, the file's hash will be different). The generated output is something like this:

<html lang="en">
    <head>
        ...
        <link href="/static/css/main.244b1f47.css" rel="stylesheet"/>
    </head>
    <body>
        ....
        <script type="text/javascript" src="/static/js/main.67225123.js"></script>
    </body>
</html>

The problem is: it doesn't do the same for index.html, but it's the index file that references these generated files, so that when the user accesses index.html, if it's already cached, it will try to request the old files (with the old hashes), because the expiration time configured in static files still applies to index.html too. Only after a client reload, that browsers will request index.html from the server again.

I tried to create an additional GET / route mapping, which would read index.html's content and send it with no cache headers, but there's currently a bug that doesn't lets this to be done.

So... how could I achieve correct caching for all static files except for index.html? Is the only solution to write my own static files handler/server and deal with all MIME-type guessing, memory caching, etc by myself, or is there an easier way?

tipsy commented 5 years ago

The bug won't bother you if you put your index file somewhere other than at the root of your static file directory, or if you name it something else.

rvaidya commented 5 years ago

I would also like to achieve this - caching only for index.html. I am currently trying to set:

staticFiles.header("Cache-Control", "no-store"); but this isn't an ideal solution since it disables caching for all static files.

@BloodShura it's been a while since this issue was filed - did you find a solution?

571 may be a solution for this if we can write an after filter to set response headers only for specific files

JoaaoVerona commented 5 years ago

@rvaidya I decided not to cache static files on Spark. Instead, I let the server compare the ETag and Last-Modified headers of the resources to decide whether to send them to the browser again.

That way, when the server sends any static file (including generated assets and index.html), it compares the ETag received from the browser (which is a "checksum"-like string of the file content in cache) with the actual ETag of the file on the server (AFAIR, this is done automatically by Jetty). If it matches, it doesn't sends the complete file content to the browser, just a 304 Not Modified status along with the resource headers (generally, only ~225 B).

The pro is that I don't need to bother with cache validation or anything related, like, ever. Browser and server compare the direct file contents. However, the browser still has to make these requests, so there's a little overhead there. Although I did not implement it because, given the available resources for the project, it would be considered overkill, one could implement HTTP2 server pushing to mitigate these additional requests.