Signed URLs are unique by default so that any URL generated is different from all others. This is usually a good thing as if the backend signs a URL that results in a unique way to download a file. This makes things simpler, as there is less interference between different users' downloads.
Unique signed URLs are good when downloads happen rarely. In the ecommerce example, users downloading products is a rare operation. Probably they fetch the file after a purchase, then maybe once or twice in the following weeks, but they won't do it multiple times a minute. Because of this, performance is not an issue: when a user downloads a file the bytes are served directly from S3 and there is no caching layer.
But there are cases when this way of operation affects user experience. In this chapter, we'll build a photo-sharing app where users can upload images, control whether other users can see their uploads, and browse other users' public photos. Using signed URLs is a requirement here: whether an image is accessible to others is a flag stored in the database.
But using signed URLs as we've discussed in the previous chapter makes a bad user experience. As each URL is unique, the same file is downloaded over and over again all the way from S3. Navigating between the pages wastes a lot of bandwidth.
In this chapter, we'll concentrate on performance: caching and latency. We'll implement a solution that allows caching both in the browser and also in a proxy. This way, a user won't download the same image every time they navigate to a new page, and even when they do need to download them, images might be cached on the edge and be served from a closer location. In terms of latency, we'll bring everything under a single domain so clients can use a single connection to download the frontend files, reach the API, and also to download and upload images using signed URLs.
We'll look into two solution to this problem. The first uses S3 signed URLs but configured in a way that allows these performance improvements. Then the second uses CloudFront signed URLs instead.
We'll take things to the limit here: a real-world project probably won't need to implement all techniques described here. But I believe it's important to know about the possibilities and tradeoffs.
The example app is a photo-sharing app. Here, users need to sign in first:
Clicking the "Login" link brings to a Cognito-default sign-in page:
After logging in (
Password.1) the page shows the user's own uploaded images:
Here, under every image is a toggler where it's possible to change from public to private and back. This changes whether the image is accessible to other users. Also, it's possible to upload new images to the collection.
Down the page is a list of other users' public images: