I am receiving images URLs from an API response and I want to cache each of those images. I tried just using cache.addAll but it does not work because the images are an opaque response. I am considering fetching each image using fetch and having the routes cache them but I am not sure as to whether this would be the best way. Are there any other better alternatives?
There's some guidance in this Stack Overflow answer that explains how to cache opaque responses; the gist of it is:
const request = new Request('https://third-party-no-cors.com/', {
mode: 'no-cors',
});
// Assume `cache` is an open instance of the Cache class.
fetch(request).then(response => cache.put(request, response));
The caveat is that your code has no way of knowing whether you're caching a valid response, or a HTTP 404 or some other error.
Related
I am currently working on performance improvements for a React-based SPA. Most of the more basic stuff is already done so I started looking into more advanced stuff such as service workers.
The app makes quite a lot of requests on each page (most of the calls are not to REST endpoints but to an endpoint that basically makes different SQL queries to the database, hence the amount of calls). The data in the DB is not updated too often so we have a local cache for the responses, but it's obviously getting lost when a user refreshes a page. This is where I wanted to use the service worker - to keep the responses either in cache store or in IndexedDB (I went with the second option). And, of course, the cache-first approach does not fit here too well as there is still a chance that the data may become stale. So I tried to implement the stale-while-revalidate strategy: fetch the data once, then if the response for a given request is already in cache, return it, but make a real request and update the cache just in case.
I tried the approach from Jake Archibald's offline cookbook but it seems like the app is still waiting for real requests to resolve even when there is a cache entry to return from (I see those responses in Network tab).
Basically the sequence seems to be the following: request > cache entry found! > need to update the cache > only then show the data. Doing the update immediately is unnecessary in my case so I was wondering if there is any way to delay that? Or, alternatively, not to wait for the "real" response to be resolved?
Here's the code that I currently have (serializeRequest, cachePut and cacheMatch are helper functions that I have to communicate with IndexedDB):
self.addEventListener('fetch', (event) => {
// some checks to get out of the event handler if certain conditions don't match...
event.respondWith(
serializeRequest(request).then((serializedRequest) => {
return cacheMatch(serializedRequest, db.post_cache).then((response) => {
const fetchPromise = fetch(request).then((networkResponse) => {
cachePut(serializedRequest, response.clone(), db.post_cache);
return networkResponse;
});
return response || fetchPromise;
});
})
);
})
Thanks in advance!
EDIT: Can this be due to the fact that I put stuff into IndexedDB instead of cache? I am sort of forced to use IndexedDB instead of the cache because those "magic endpoints" are POST instead of GET (because of the fact they require the body) and POST cannot be inserted into the cache...
I am using cy.intercept to verify requests made to an API.
Whilst asserts are working great an issue is that my requests are actually sent to an API.
So, what do I do to stop actual requests from being sent to an API?
This is what I am doing right now:
cy.intercept('api/login', []).as('login')
cy.get('[data-cy=login]')
.click()
.wait('#login')
.its('request')
.then(({ headers, body }) => {
// perform asserts...
})
The way to reply from the intercept instead of the API is to use cy.intercept(url, staticResponse) where the simplest staticResponse is an empty object {},
cy.intercept('api/login', {}).as('login')
Obviously if your app needs some properties in the response, you should add those, or use a fixture, etc
Ref StaticResponse objects.
I'm wondering if a fetch call in a ServiceWorker uses the normal browser cache or bypasses it and sends the request always to the server
For example. Does the fetch call on line 5 first look in the browser cache or not.
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return cache.match(event.request).then(function (response) {
return response || fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
That's a good question. And the answer is: fetch inside the SW works just like fetch in the browser context. This means that the browser's HTTP cache is checked and only after that the network is consulted. Fetch from the SW doesn't bypass the HTTP cache.
This comes with a potential for a race condition if you're not careful with how you name your static assets.
Example:
asset.css is served from the server with max-age: 1y
after the first request for it the browser's HTTP cache has it
now the file's contents are updated; the file is different but the name is still the same (asset.css)
any fetch event to the file, asset.css, is now served from the HTTP cache and any logic that the SW implements to check the file from the server is actually leading to getting the initial file from step 1 from the HTTP cache
at this point the file on the server could be incompatible with some other files that are cached and something breaks
Mitigations:
1. Always change the name of the static asset when the content changes
2. Include a query string (do not ask for asset.css, but for asset.css?timestamporsomething)
Required very good reading: https://jakearchibald.com/2016/caching-best-practices/
I'm doing a blog-app currently, and I'm struggling to find a way to redirect/send a specific status and then act accordingly.
For example, I have a function that saves data in mongodb using mongoose. Then if no errors occurred 200 status.
newArticle.save(function(err){
if (err) throw err;
else {
res.sendStatus(200);
}
});
I want to be able to "fetch" this status (I'm using react for my views and routes and superagent for my ajax request), and then do something, for example, If my article is successfully added then load a certain component on the page that will have an h1 saying : Great job on posting an article.
So this is the first part.
The second part is, for everything 404 or 500 errors I want express to redirect me from for example : myblog.com -> myblog.com/something and then with my react router simply render some basic 404 pages, I do not know how to do that, I'm searching a lot and couldn't find something...
And, since I lack knowledge in the HTTP basics like how server and client talk to each other, if you have any good article/books to recommend I'd like to know about.
For first part. Depending on if you are using state or data library like flux or redux, if not, you can just have ajax response will have the HTTP status from your server. Using that, you can use setState to set a state property called something like isArticleSaveSucessful. Then simply render your success message component if that key is true.
Second part. For the better user experience which is I think what you intended, the url should still be what the user intended, ie, blog.com/bad-article-name but the page should render a 404. Very similar to above, when the API response comes back, setState accordingly, something like articleNotFound. Then in your render function, do an if check on the the state and if it is true, then render your error component.
I am using an API. The resquest-response time on the API takes too long time. So, due to this problem, I want to store the response on the Server but not on the browser. This is because, I want to display the result from cache for similar searches. I know, there are limitations on the accuracy on cached data, but that's another part which I don't want to include here.
I am using laravel framework and using this code for current moment as in the laravel documentation.
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
The problem with this code is, it stores cache on the browser only. But I want to store it on Server. I have heard about the Memcached but could not implement it. I have also heard of apc_store() but I think it stores on local. So, How can I store cache on server?
Similar to Cache::put(), you can use Cache::pull() to check for data saved (on the server).
// Check cache for data
$cachedData = Cache::pull($key);
// Get new data if no cache
if (! $cachedData) {
$newData = 'New Data';
$expiresAt = Carbon::now()->addMinutes(10);
// Save new data to cache
$cachedData = Cache::put($key, $newData, $expiresAt);
}
echo $cachedData;