Better 404 pages for App Engine static websites
There’s a semi-documented feature in App Engine’s static files handlers that can be super useful: require_matching_file: true. The documentation for app.yaml’s static handlers does not mention this field, but we can find it in the RPC docs for the App Engine Admin API.
require_matching_file - Whether this handler should match the request if the file referenced by the handler does not exist.
I find that definition hard to parse, here’s my attempt: when true, the requested file must exist in order for a request to match the handler; if the file does not exist, then the request will skip this handler.
The default behaviour is equivalent to require_matching_file: false. Suppose you have an app with static HTML generated for upload in a “dist” directory, and the default main.py as your Python script:
# app.yaml
runtime: python314
handlers:
- url: / # Match a request for anything
static_dir: dist
A request for “/foo.html” will match the first handler. If “dist/foo.html” exists, it will be served. If “dist/foo.html” does not exist, then the user will see App Engine’s default 404 response.
But specifying require_matching_file: true changes the behaviour to fall through to the next handler if there is no file:
# app.yaml
runtime: python314
handlers:
- url: / # Match a request for anything
static_dir: dist
require_matching_file: true # But only match if the requested file exists
- url: /.* # All other requests
script: automatic
Now, a request for “/foo.html” matches the pattern for the first handler, but fails the match when “dist/foo.html” does not exist. But instead of returning a 404 response, App Engine sees if the next handler will match. The next handler in this case is the Python script at main.py, which gives you an opportunity to return a nicer looking, custom 404 response (or a redirect, or a 200, or whatever).
This is cool. You can use App Engine’s static files handlers to serve all the static content, but when there’s no match, have the dynamic script handler respond with a pretty 404. Generating a response with a dynamic handler is going to be slower than a response from a static handler, but gives you all the flexibility.