Google App Engine serves static CSS files with wrong mime-type - google-app-engine

I've been working on a new site to be hosted on Google App Engine. I've been deploying my app to a development project and it is hosted here:
Development: https://herdboss-dev.appspot.com/
It works fine.
But when I take the exact same code and deploy it to my other project which going to be the real, production website, it is serving some of the css as application/octet-stream instead of text/css and so those files aren't being parsed by the browser, so almost all of my css is not working on the production site:
Production: https://herdboss-prod.appspot.com/
Even weirder is that SOME of the css is being served correctly. /css/normalize.css is being served as text/css but /css/site.css is being served as application/octet-stream.
https://herdboss-prod.appspot.com/css/normalize.css
https://herdboss-prod.appspot.com/css/site.css
https://herdboss-prod.appspot.com/js/jquery-ui-1.12.1.custom-theme/jquery-ui.min.css
My app.yaml has a static handler for css files:
- url: /css
static_dir: css
secure: always
I tried adding a mime_type as well but that didn't change anything:
- url: /css
static_dir: css
mime_type: 'text/css'
secure: always
EDIT:
While experimenting, I cut my site.css in half, deployed, and then it started serving correctly. Then I reinstated the full size site.css, deployed... and it's still serving properly now.
But my jquery-ui.min.css is still serving as octet-stream. This is crazy.
EDIT2:
And it's serving my svg's with the wrong mime type as well.
Is mime-typing just utterly broken in the GAE? If so, why is it working on my dev gae?

My solution was:
duplicate the offending file and rename it
change one byte (otherwise it will not be uploaded/updated)
verify that it downloads as stylesheet
use the renamed, changed css file in your html
Wait for the original to get served correctly: after about 24h the problem fixed itself
There is an issue on the GAE issue tracker: https://issuetracker.google.com/issues/186012458
Initially, I tested a workaround but this workaround broke after a day: I modified my HTML to load the stylesheets from a version server basically cross-site as (hxxps://VERSION-dot-SERVER.appspot.com/static/stylesheet.css). The version server served the correct mime-type ... but only for some time.
I suspect the problem is a wrong mime-type due to an extremely rare race condition (cache access/refresh during upload?). It is simply not possible to trick the Google Frontend to refresh the file. Even appending .../styles.css?x=1 or switching back to an older code version will not trigger a refresh.
Files and their mime-types seem to be stored based on their hashed-values, so re-upload of a file with the same content has no effect even if it is simply renamed. You will see an "uploaded 0 files" message if you deploy a version with a duplicate file. It has to be changed and renamed.

I did check both of your sites: https://herdboss-prod.appspot.com/, https://herdboss-prod.appspot.com/
I can see that you have several CSS files: normalize.css, jquery-ui.min.css, base-min.css, grids-min.css, grids-responsive-custom.css, css?family=Open+Sans,
site.css, ie-is-terrible.css, css_compiled.css.
All of them served correctly as Type: stylesheet
If you encounter this problem I recommend performing following test:
Check content type in Developer Console > Network with the option Disable Cache > And reload page. If it helps: clean cache of the browser.
Check content of the page in different browser, as content can be interpreted differently depending on the rendering engine.
If 1 and 2 does not work, and you are using nginx, it is most probably configuration problem. Change the file /etc/nginx/conf.d/default.conf. Put /etc/nginx/mime.types in the 'http' section:
http / {
include /etc/nginx/mime.types;
default_type application/octet-stream;
....
}
if it is still not working, move it to location section
location / {
include /etc/nginx/mime.types;
...
}

Related

How do I set the favicon used when serving files from DNN Platform?

When serving static files (e.g. PDFs) from a DNN website, the default DNN favicon shows up, rather than the favicon configured for the site. How can we get the site's main favicon to be used when serving static files?
When serving static files, DNN isn't part of the request. There's also not a way for the web server to tell the browser an alternate location for the favicon. So the browser looks in the default location, /favicon.ico. A DNN favicon is included here in the default installation package. Assuming you aren't hosting sites with different favicons in your DNN installation, you can simply overwrite DNN's favicon.ico file in the root of the file system with your custom favicon.ico file (this will require access to the web server's file system, it's not exposed through the web interface by default).
If you host multiple sites with different favicon.ico files, there's not as simple of an answer here. You could probably use URL Rewrite rules to read the host being used in the request, and redirect /favicon.ico requests to the correct spot.

Cache busting with CRA React

When I updated my site, run npm run build and upload the new files to the server I am still looking the old version of my site.
Without React, I can see the new version of my site with cache-busting. I do this:
Previous file
<link rel="stylesheet" href="/css/styles.css">
New file
<link rel="stylesheet" href="/css/styles.css?abcde">
How can I do something like this or to achieve cache busting with create react app?
There are many threads in the GitHub of create react app about this but no one has a proper/simple answer.
EDIT: create-react-app v2 now have the service worker disabled by default
This answer only apply for CRA v1
This is probably because of your web worker.
If you look into your index.js file you can see
registerServiceWorker();
Never wondered what it did? If we take a look at the file it got imported from we can see
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read {URL}
// This link also includes instructions on opting out of this behavior.
If you want to delete the web worker, don't just delete the line. Import unregister and call it in your file instead of the register.
import { unregister } from './registerServiceWorker';
and then call
unregister()
P.S. When you unregister, it will take at least one refresh to make it work
I had the same issue when I use create-react-app ( and deploy to heroku). It keeps showing the old version of my app 😡.
I found the problem seems to be on the browser side, it caches my old index.html with its outdated js bundle
You may want to add the following to your server side response header
"Cache-Control": "no-store, no-cache"
or if you are also using heroku create-react-app-buildpack, update the static.json file
"headers": {
"/**": {
"Cache-Control": "no-store, no-cache"
}
}
I think in this way you can still keep that poor service worker 😂, and the latest content will be shown on the N+1 load (second refresh)
Hope this helps...
As mentioned by some of the previous answers here, both the service worker and the (lack of) cache headers can conspire against you when it comes to seeing old versions of your React app.
The React docs state the following when it comes to caching:
Using Cache-Control: max-age=31536000 for your build/static
assets, and Cache-Control: no-cache for everything else is a safe
and effective starting point that ensures your user's browser will
always check for an updated index.html file, and will cache all of
the build/static files for one year. Note that you can use the one
year expiration on build/static safely because the file contents
hash is embedded into the filename.
As mentioned by #squarism, older versions of create-react-app defaulted to opt-out of service worker registration, while newer versions are opt-in. You can read more about that in the official docs. It's quite a straightforward process to match you configuration to the latest template if you started with an older version of create-react-app and you want to switch to the new behaviour.
Related questions:
How to avoid caching for create-react-app
ReactJS: How to prevent browser from caching static files?
how to clear browser cache in reactjs
If your problem is with resources statically referenced in index.html, such as .css files or additional .js files (e.g. configuration files), you can declare a React environment variable, assign a unique value to it and reference it in your index.html file.
In your build script (bash):
REACT_APP_CACHE_BUST={e.g. build number from a CI tool} npm run build
In your index.html:
<link rel="stylesheet" href="%PUBLIC_URL%/index.css?cachebust=%REACT_APP_CACHE_BUST%" />
The variable name has to start with REACT_APP_. More about environment variables in React: https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables.
It appears that they changed from opt-out to opt-in with regards to the service worker. Here's the commit that changed the README and it has examples similar to Kerry G's answer:
https://github.com/facebook/create-react-app/commit/1b2813144b3b0e731d8f404a8169e6fa5916dde4#diff-4e6ec56f74ee42069aac401a4fe448ad

How to prevent file caching in Google AppEngine?

How do we stop App Engine from using caches of previously loaded files?
According to Google's documents here under "App Caching", they suggest that App Engine caches files that are loaded. They seem to suggest that it is related to the presence of their main() function. However, we removed all references to main() and find that App Engine is still using cached files.
We also tried this HTML below per this answer, but are still getting cached results in the browser. (When we return to the home page - the tables which load JSON are not getting the new file results - they are receiving the old versions of the files.)
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
Here is our app.yaml
application: OurApp
version: 0.5
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /stylesheets
static_dir: stylesheets
handlers:
- url: /scripts
static_dir: scripts
- url: /.*
script: main.app
Any suggestions for how to prevent this file load caching behavior in App Engine?
If the files you are trying to update are static files, such as those inside the /stylesheets or /scripts folders from your project, you should take a look at this doc for static cache expiration for GAE projects in the standard environment for Pyhton. According to it, "files are likely to be cached by the user's browser, as well as by intermediate caching proxy servers such as Internet Service Providers". But I've found a way to flush static files cached by your app on Google Cloud.
Head to your Google Cloud Console and open your project. Under the left hamburger menu, head to Storage -> Browser. There you should find at least one Bucket: your-project-name.appspot.com. Under the Lifecycle column, click on the link with respect to your-project-name.appspot.com. Delete any existing rules, since they may conflict with the one you will create now.
Create a new rule by clicking on the 'Add rule' button. For the object conditions, choose only the 'Newer version' option and set it to 1. Don't forget to click on the 'Continue' button. For the action, select 'Delete' and click on the 'Continue' button. Save your new rule.
This new rule will take up to 24 hours to take effect, but at least for my project it took only a few minutes. Once it is up and running, the version of the files being served by your app under your-project-name.appspot.com will always be the latest deployed, solving the problem. Also, if you are routinely editing your static files, you should remove any expiration element from handlers related to those static files and the default_expiration element from the app.yaml file, which will help avoid unintended caching by other servers.
The section of the doc that you cite has to do with how python files on the server side are handled. It's a server-side optimization, and is entirely separate from how a browser caches HTML from your application.
You can specify additional HTTP headers (e.g., Cache-Control) in app.yaml. See the Static File Handlers section in the doc. You can also add headers dynamically via the self.response.header. This is discussed, with a small example, in the Responses section of the doc.

Google App Engine - default MIME type

Long story short:
I'm building a static web application which seems to work fine locally when served with the Node http-server, but when deployed to Google App Engine, has issues. I've traced the problem to the content-type header: when serving locally, some of my files (from an Emscripten library) are served with application/octet-stream; charset=utf-8 which works. When served from App Engine, they're served with simply application/octet-stream, which does not work. I've been able to verify this by adding a mime_type: application/octet-stream; charset=utf-8 line to one of my app.yaml handlers, but there are dozens or hundreds of files intermingled with different MIME types. I don't want to mark them all as octet-stream if I don't have to.
So is there a way in app.yaml to simply specify a default mimetype besides application/octet-stream? If not, I'll have to get much more creative with my handler matchers.
You can't set a default global mime type, but you can (as you mention) get creative. This is a good example of an app.yaml file for a static website, it's not unusual to define cases for each different file type, in order to have fine control over placement/mime.
In your case, you might wish to extend on the following idea:
- url: /(.*\.(svg|svgz))
mime_type: images/svg+xml
static_files: static/\1
upload: static/(.*\.(svg|svgz))
Using this pattern you can match multiple file types with the same mime type. Might be the quickest (& dirtiest?) path to solve your problem.
Here's another app.yaml example for further reference.

Uploading images along with Google App Engine

I'm working on a Google App Engine project.
My app is working and looking correct locally, but when I try to upload images in an image directory, they're not being displayed at appspot.
As a little troubleshoot, I put a HTML page in "/images/page2.html" and I can load that page at the appspot, but my pages don't display my images. So, it's not a problem with my path.
As another sanity check, I'm also uploading a style sheet directory with .css code in it, and that's being read properly.
I have a suspicion that the problem lies in my app.yaml file.
Any ideas?
I don't want to paste all the code here, but here are some of the key lines. The first two work fine. The third does not work:
<link type="text/css" rel="stylesheet" href="/stylesheets/style.css" />
Page 2
<img src="/images/img.gif">
This is my app.yaml file
application: myApp
version: 1
runtime: python
api_version: 1
handlers:
- url: /stylesheets
static_dir: stylesheets
- url: /images
static_dir: images
- url: /.*
script: helloworld.py
You have to configure app.yaml for static content such as images and css files
Example:
url: /(.*\.(gif|png|jpg))
static_files: static/\1
upload: static/(.*\.(gif|png|jpg))
For more info check out:
http://code.google.com/appengine/docs/configuringanapp.html
I'll bet your problem is that you're using Windows.
If that's the case, I believe you need a preceding slash for your static_dir value.
I am using the Java version of App engine, and I faced a similar issues with the server not able to serve static images.
What worked ultimately was to change the AppEngine config file "appengine-web.xml" in my case to contain
<static-files>
<include path="**.*"/>
<include path="/images/**.*" />
</static-files>
My images are in the /images directory and HTML and CSS are in . directory which is at the WEB-INF level
#jamtoday The preceding slash didn't make a difference, but it did get me started figuring out what each app needs to be told what about my directory structure.
So, I have nothing very conclusive to add, but I wanted to follow up, because I got it working, but I didn't explore all the issues after I got it working.
One change that helped was to stop working from a HwlloWorld/src/ directory and start working in the HelloWorld/ directory. It seems like the dev_appserver picked up all the dependencies, but the remote server didn't. Essentially, the relative path of my local links didn't match the relative path of the links after uploading.
I also realized that the dev-appserver relies on the .yaml file, as well as the appcfg script. That is. . .if you add a directory to your project, and then try to link to files in that directory, you need to add the directory to the .yaml file, and then restart the dev-appserver to pick up on this.
So, there are probably ways to handle what I was originally trying to do if you give the .yaml file the right info, but changing to a different directory structure locally handled it for me.
<img src="/images/img.gif">
this line can't show you the image.
Try this one:
1-Create a class to handle "image request"
class GetImage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'image/jpg'
self.response.out.write(image_object)
2-In your page.html:
<img src="/image"
3-At the main function in your code.py:
application = webapp.WSGIApplication(('/image', GetImage), debug=True)
have fun

Resources