Is there any way to load images from S3 to browser only if they were changed, by sending If-Modified-Since header?
It should be enabled by default on browsers and S3 but tests saying that images are loading on every refresh.
Amazon S3 supports the If-Modified-Since header already, as well as the related If-None-Match (which uses an ETag instead of a date).
So, the way to load images only if they were changed is to actually use the If-Modified-Since, or If-None-Match if you have the Etag. However, since you are talking about loading it to a browser, most browsers will already be doing this unless you have done something funky to disable browser caching.
See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html#RESTObjectGET-requests-request-headers for details on the supported headers.
Are you experiencing a situation where the browser is still loading the images from S3 even if they haven't been changed? If so, do you have more details on that, e.g. the browser, version, and something like a Chrome network tab HAR file illustrating the symptoms?
By default, it should just work on both sides with no custom changes. I just replicated by uploading a fresh png image file to S3. In a fresh browser window, I opened the dev tools and loaded the network tab. I ensured that the 'disable caching' was UNticked, and 'preserve log' was ticked (to keep the log over multiple F5 refreshes).
I loaded the image and then hit F5 to reload twice. The result was:
As you can see, the first load was with a 200 status, the other requests received 304.
Related
Our team is building a web app that allows users to download video files. We currently host our files on AWS S3, but since our site doesn't reside on AWS, we can't use <a href="blah"> to prompt download. If we use that html element, users simply get redirected to a video player - which is fine, but Safari on mobile doesn't allow for users to download the video file via the video player.
We found that manually setting the file's content disposition to attachment on S3 works, but we have not found a way to automate that. We tried adding a content-disposition: attachment key-value pairing in our payload, which works, but adds a "User defined" meta data in the form of x-amz-meta-content-disposition, which doesn't work as the file could not be downloaded as an attachment. It seems only "System defined" works.
Has anyone ever encountered this issue before and found a workaround?
see screenshot for what I'm referencing
You can set the content disposition when the file is created.
This is done by uploading the file via a presigned url.
See https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html for details on the presigned urls.
Alternatively you can use a presigned url to return to get the file from S3 and override the content disposition header on the GET request.
I have set up a CloudFront on top of multiple S3 buckets (in different regions) to provide a fast stable version of my webapp. This webapp is implemented with React which means it's all one single HTML file and one single Javascript file.
Using the routing mechanism of React, all the paths in the URL are handled within the code. This means if I click on a link like www.example.com/users, there won't be a request sent to the server. Instead, the client code will render the appropriate page without any consultation with the server (I'm just talking about the HTML and not considering the data). This means that if some user types in the given URL, the server should return the index.html (the only HTML file I have) which then will take care of the URL on the client-side. In other words, all the requests sent to the server should either return the HTML file or the Javascript file I mentioned earlier. Even the requests that are pointing to none-existing files.
In order to implement this requirement, I asked this question and I got an answer like this:
I need to set up an error page for my distribution on CloudFront and
redirect all the 403 (Forbidden) requests to /index.html file. This
is because when the request is pointing to a nonexisting file on S3,
S3 will return 403 to CloudFront due to the lack of listing
permission. Or I can grant the listing permission and instead handle
the 404 error (I didn't test this latter option).
Anyways, I set this up and it works perfectly - for a few hours. But then, for some unknown reason, the request to the Javascript file also returns the HTML file. And of course, all I'm getting back is actually coming from CloudFront's cache which means, no matter how many times I send the request, it will keep returning the same value. That is until I invalidate the cache on CloudFront which will solve the problem for few more hours. And we go around and around.
Even though I'm not sure why this happens but my guess is that at some point the S3 buck is inaccessible to CloudFront which will result in CloudFront caching the index.html. What can I do about this?
I think I found the problem:
MAKE SURE YOUR STATIC CONTENT ON ALL THE S3 BUCKETS ARE IDENTICAL!!!
In my case, the Javascript filename is automatically generated by Webpack which means it's random. And since different regions were "compiled" separated, their filenames differed.
I'm using AWS Cloudfront to service audio files to user. Recently several user reported that they are unable to play my audio file. A browser refresh is required to make it work if the audio is stuck.
In the Google Chrome console, it outputs
Failed to load resource:
net::ERR_CACHE_OPERATION_NOT_SUPPORTED
I already have a cache settings in my Cloudfront Behavior settings,
Only default settings is on the origin s3 bucket.
CF cache settings
Any suggestion?
I faced the same issue with a cloudfront video failing to load due to this error. I was able to resolve it using javascript like this:
var videoLink = videoControl1.children[0].src; // videoControl1 is the HTML5 video element, should work similarly for audio.
if (!videoControl1.readyState){
videoControl1.children[0].src = videoLink + "?v=" + Math.random();
videoControl1.load();
}
I followed the suggestion from here: https://github.com/igvteam/igv.js/issues/424#issuecomment-336336788
If you are going to change audio/video source dynamically and play that video/audio, you need to load with load() JS function first that resource before playing.
Let's say I have two files: one for safari and one for Firefox.
I want to check User-Agent and return file based on the User-Agent.
How do I do this without adding external server?
You can't do this without adding an extra server.
S3 supports static content. It does not¹ vary its response based on request headers.
CloudFront relies on the origin server if content needs to vary based on request headers. Note that by default, CloudFront doesn't forward most headers to the origin, but this can be changed in the cache behavior configuration. If you forward the User-Agent header to the origin, your cache hit rate drops dramatically, since CloudFront has no choice but to assume any and every change in the user agent string could trigger a change in the response, so an object in the cache that was requested by a specific user agent string will only be served to a future browser with an identical user agent string. It will cache each different copy, but this still hurts your hit rate. If you only want to know the general type of browser, CloudFront can inject special headers to tell the origin whether the user agent is desktop, smart-tv, mobile, or tablet, without actually forwarding the user agent string and causing the same negative impact on the cache hit ratio.
So CloudFront will correctly cache the appropriate version of a page for each unique user agent... but the origin server must implement the actual content selection logic. And when the origin is S3, that isn't supported -- unless you have a server between CloudFront and S3. This is a perfectly valid configuration -- I have such a setup, with a server that rewrites the request path received from CloudFront before sending the request to S3, then returns the content from S3 back to CloudFront, which returns the content to the browser.
AWS Lambda would be a potential candidate for an application like this, acting as the necessary server (a serverless server, if you will) between CloudFront and S3... but it does not yet suport binary data, so for anything other than text, that isn't an option, either.
¹At least, not in any sense that is relevant, here. Exceptions exist for CORS and when access is granted or denied based on a limited subset of request headers.
I'm trying to set a Content-Security-Policy header for an html file I'm serving via s3/cloudfront. I'm using the web-based AWS console. Whenever I try to add the header:
it doesn't seem to respect it. What can I do to make sure this header is served?
I'm having the same problem (using S3/CloudFront) and it appears there is currently no way to set this up easily.
S3 has a whitelist of the headers permitted, and Content-Security-Policy is not on it. Whilst it is true you can use the prefixed x-amz-meta-Content-Security-Policy, this is unhelpful as there is no browser support for it.
There are two options I can see.
1) you can serve the html content from a webserver on an EC2 instance and set that up as another CloudFront origin. Not really a great solution.
2) include the CSP as a meta tag within your html document:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src http://*.foobar.com 'self'">
...
This option is not as widely supported by browsers, but it appears to work with both Webkit and Firefox, so the current Chrome, Firefox, Safari (and IOS 7 Safari) seem to support it.
I chose 2 as it was the simpler/cheaper/faster solution and I hope AWS will add the CSP header in the future.
S3/CloudFront takes any headers that the origin set and forward those to the client, but you can't set custom headers on you response directly.
You can use Lambda#Edge function that can inject security headers through CloudFront.
Here is how the process works: (reference aws blog)
Viewer navigates to website.
Before CloudFront serves content from the cache it will trigger any
Lambda function associated with the Viewer Request trigger for that
behavior.
CloudFront serves content from the cache if available, otherwise it
goes to step 4.
Only after CloudFront cache ‘Miss’, Origin Request trigger is fired
for that behavior.
S3 Origin returns content.
After content is returned from S3 but before being cached in
CloudFront, Origin Response trigger is fired.
After content is cached in CloudFront, Viewer Response trigger is
fired and is the final step before viewer receives content.
Viewer receives content.
Below is the blog from aws on how to do this step by step.
https://aws.amazon.com/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/
If you are testing through CloudFront, have you made sure you have invalidated the cached objects? Can you try to upload a completely new file and then try accessing it via CF and see if the header is still not there?
Update
Seems like custom metadata will not work as expected as per DOC. Any metadata other than the ones supported by S3 (the ones displayed in the dropdown) will have to be prefixed with x-amz-meta-