Incremental updates using browser cache

The client (AngularJS application) receives quite large lists from the server. Lists can contain hundreds or thousands of items, which can mean several uncompressed megabytes (and some users (admins) receive much more data).

I do not plan for the client to get partial results, since sorting and filtering should not bother the server.

Compression works fine (around 10), and since lists don't change often, 304 NOT MODIFIED helps too. But another important optimization is missing:

As a typical list change is pretty small (like changing two items and adding a new one), passing the changes sounds just like a good idea. I wonder how to do it right.

Something like GET /offer/123/items should always return all items in offer number 123, right? Compression and 304 can be used here, but without incremental updates. A request like GET /offer/123/items?since=1495765733 sounds like a way, but browser caching is not used:

  • nothing has changed and the answer is empty (and caching it makes no sense)
  • or something has changed, the client updates its state and no longer requests changes from 1495765733 (and caching makes this even less noticeable).

Obviously, when using the "from" request, nothing will be cached for the "resource" (the original request will be used only once or not at all).

Therefore, I cannot rely on the browser cache, and I can only use localStorage or sessionStorage , which have several drawbacks:

  • it is limited to a few megabytes (the HTTP browser cache can be much larger and is processed automatically)
  • I need to implement some replacement strategy when I get into the limit
  • already compressed data is stored in the browser cache, which I donโ€™t receive (I would have to compress it)
  • it does not work for users (administrators) receiving large lists, since even one list may already be a limited limit
  • it is cleared upon exiting the system (customer requirement)

Given that HTML 5 and HTTP 2.0, this is pretty unsatisfactory. What am I missing?

Can I use the HTTP browser cache along with incremental updates?

+7
source share
3 answers

I think there is one thing you are missing: in short, the headlines. What I think you could do, and which would fit (most) of your requirements, would be the following:

  • The first GET /offer/123/items runs fine, nothing special.
  • Subsequent GET /offer/123/items will be sent with the header Fetched-At: 1495765733 , pointing to your server when sending the initial request.

From this point on, two scenarios are possible.

  • Or there is no change, and you can send 304.
  • If there is a change, return the new elements, as the previously sent time stamp has headers, but set Cache-Control: no-cache from your answer.

This will lead you to the fact that you can have incremental updates, with caching elements of the initial megabyte.

However, there is another drawback: caching is performed only once, it will not cache updates. You said that your lists are often not updated, so they may work for you already, but if you really want to move it further, I could think of one more thing.

After receiving an incremental update, you can run another request in the background without a Fetched-At header, which will not be used by your application at all, but your http cache will just be updated. This should not be as bad as it seems in terms of performance, since your infrastructure will not update its data with a new one (and potentially run re-renders), the only noticeable drawback may be the network and memory consumption. On mobile devices, this can be problematic, but it doesnโ€™t seem like an application designed to be displayed on them anyway.

I absolutely do not know your precedent and just throw it away, but are you really sure that it will not work to do some kind of pagination? Megabytes of data sound a lot to display and process normal people;)

+4
source

I will completely abandon the request / response cycle and move on to the push model. In particular, WebSockets .

This is the standard technology used on financial trading sites serving real-time data tables. Here is one of these production applications that demonstrate the power of WebSockets:

https://www.poloniex.com/exchange#btc_eth

WebSocket applications have two types of states: global and user. The link above will show three global data tables. When you are logged in, two additional user data tables are displayed below.

This is not HTTP; you can't just tickle it in the Java Servlet. You will need to run a separate process on your server that communicates via TCP. The good news is that there are mature solutions that are readily available. A Java-based solution with a very decent free licensing option that includes both client and server APIs (and integrates with Angular2), Lightstreamer . They have a well organized demo page. There are also adapters available to integrate with your data sources.

You may not dare to abandon your existing approach to servlet, but in the long run it will be less headaches and surprising. An HTTP poll, even with well-designed header-only requests, does not scale well with large lists that are frequently updated.

---------- EDIT ----------

Since list updates are infrequent, WebSockets will probably go overboard. Based on the additional details provided by the comments on this answer, I would recommend DOM-based, an AJAX-modified sorter and filter, such as DataTables , which has built- in caching options . To reuse client data in sessions, you need to modify the ajax requests in the previous link to save the current data in the table to localStorage after each ajax request and when the client starts a new session, fill the table with this data. This will allow the plugin to manage browser-based filtering, sorting, caching and saving.

+3
source

I am thinking of something similar to the Apers idea, but using two queries. The idea is still incomplete, so carry me ...

  • The client requests GET /offer/123/items , possibly with ETag and Fetched-At .

Server is responding

  • 200 and a complete list if there is no title, or when there are too many changes, since the Fetched-At label is Fetched-At
  • 304 if nothing has changed since then
  • 304 and a special Fetch-More header telling the client that more data will be selected differently

The latter case disrupts HTTP, but AFAIK is the only way for the browser to cache everything I want it to cache. Since the entire message is encrypted, proxies cannot punish me for violating the specification.

The client responds to Fetch-Errata by requesting GET /offer/123/items/errata . Thus, the resource is divided into two requests. The split is ugly, but the $ http corner interceptor can hide the ugliness from the application.

The second request is also cached, as well as the Fetched-At header. The details are not clear, but some kind of strong gauntlet makes me believe that it can work. Actually, errors can be inaccurate, but still useful and create errors themselves.

With HTTP / 1.1, more requests can mean a longer latency, but having a pair of them should be beneficial because of the bandwidth saved. The server can decide when to stop.

Using HTTP / 2, you can send multiple requests at once. The server could handle them efficiently because it knows that they belong to each other. A few more manual ones ...

I find this idea strange, but interesting, and I look forward to comments. Feel free to me, but please leave an explanation.

+2
source

Source: https://habr.com/ru/post/1268248/


All Articles