Reputation: 3853
The Problem
The web page needs to download several files, say ${some_id}.file
.
But
https://some.cloud.com/${some_generated_token}
, which are not permanent URLs.If the front-end simply does:
fetch(`https://some.cloud.com/${some_generated_token}`)
It will have to download every time the page get refreshed because the URL is changing so it cannot use those e-tag stuff for caching, and the users won't like it.
Approach 1
Write my own file server so the front-end downloads from https://my-server.com/download/${some_id}.file
.
The server checks the user's permission before the download. And if the check passes, send redirect (302 moved temporarily) to the real downloading url https://some.cloud.com/${some_generated_token}
, otherwise respond with error.
Maybe I should put an etag
header in the response, copied from the real one. I'm not sure if this will work. Is it possible to make the browser cache files that are downloaded from redirected URLs?
Approach 2
Manually implement a caching system for the client side, which downloads the real file under the hood when necessary. So the file are actually loaded from cache rather than from the cloud. Files are identified by something like ${some_id}_${checksum}
.
The downside might be that I have to manage the storage manually. (So either I have to bother the user with another setting to decide the capacity, or the browser decide this and I have no way to negotiate. I'm not sure about this.)
So what is the best / possible way to do that? And how to implement it?
Upvotes: 0
Views: 558
Reputation: 13598
If you want security, then it's either the cloud service is "smart" (server side checking), or your frontend is "smart" (own caching own checks by query strings).
There is no easy way to wanting security, and yet, cheap "unsmart" service.
One of the solution is using fetch(url, { header: { Authorization: token}}) then use service like cloudfront.
your url remains unchanged so likely it will gets cached. Authorization header changes, however if you use jwt token, the token validity is very long, so likely it doesn't change unless you logout/login.
E.g. Cloudfront-like services
In the case of cloudfront for example, you can forward header authorization code to your origin to request for file, and you can choose to cache the header.
User request -> Cloudfront -> Forward authorization header to origin -> origin check and return file.
If you want savings on external bandwidth, you can use Lambda as origin to check authorization code + retrieve from s3 to be served from cloud front, aws internal bandwidth is mostly free.
lambda -> retrieve from s3 -> return to cloudfront.
Caching content based on request headers
Do note however, it's not 100% secure.
disclaimer: If you are putting files on the cloud, without a one time signedUrl, no matter what you do, it's not secure.
Upvotes: 1
Reputation: 19997
I recommend approach 2, client side caching, if the id of resource can be resolved/informed somehow on the client side.
Service Worker API can be helpful to your use case. And the specific section, quoted from MDN:
Your service worker can respond to requests using the
FetchEvent
event. You can modify the response to these requests in any way you want, using theFetchEvent.respondWith()
method.
Example service worker code:
function deriveStableUrl(request) {
// somehow decide a stable URL for the varying token URL for the same resource
// note that, this URL is not for network fetching, but merely a key to index the underlying resource in the cache.
return stableUrl;
}
addEventListener('fetch', event => {
event.respondWith(async function() {
// Open 'default' cache object, or you can decide the name of your choice.
const cache = await caches.open('default');
// Try to get the response from a cache.
const url = deriveStableUrl(event.request);
const cachedResponse = await cache.match(url);
// Return it if we found one.
if (cachedResponse) return cachedResponse;
// If we didn't find a match in the cache, use the network.
return fetch(event.request).then(resp => {
// Cache it with the stable URL as key.
cache.put(url, resp);
return resp;
})
}());
});
Upvotes: 1
Reputation: 26380
Approach 3 (smart proxying): Provide a stable URL on your own host (where the front-end is served from), passing the token in a header, and have that end-point pull the file from the cloud system (using the token) and forward it to the front-end. This would only make sense if A) the file size is not so big, that it inflicts significant cost to your own systems transfer volume and B) that you do actually have a back-end to pull this off from.
Upvotes: 1