22

There are guides and questions all over the place on how to do this, but never really a concrete answer that is satisfactory. Basically, I'm wondering if it's possible to host a static SPA (HTML/CSS/JS) in GCP Cloud Storage.

The main caveat of this is that the SPA has its own routing system (ReactRouter) so I want all paths to be served by index.html.

Most guides will tell you to set the ErrorDocument to index.html instead of 404.html. While this is a clever hack, it causes the site's HTTP response code to be 404 which is a disaster for SEO or monitoring tools. So that will work, as long as I can change the response code.

Is there any way to make this work? I have CloudFlare up and running too but from what I can tell there are no ways to trim the path or change the response status from there.

Matt Dodge
  • 10,833
  • 7
  • 38
  • 58

4 Answers4

3

A good approach here is to use Google App Engine to host a static SPA. https://cloud.google.com/appengine/docs/standard/python/getting-started/hosting-a-static-website

You can use the app.yaml file to map urls to the static file. Here’s an example:

runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /
  static_files: www/index.html
  upload: www/index.html

- url: /(.*)
  static_files: www/\1
  upload: www/(.*)

Documentation for app.yaml https://cloud.google.com/appengine/docs/standard/python/config/appref

  • 3
    Thanks for the answer, this is definitely a viable option. Unfortunately it's also a somewhat heavy and costly option when all we're really talking about is serving up some HTML/JS files. We want to be hosting dozens of these SPAs so I'm hoping to find a way to do it with GCP buckets as the backend. – Matt Dodge Apr 03 '18 at 17:36
  • I can confirm that it's not possible to change the response code with the bucket redirection. So if you'd like to serve all paths by index.html using buckets, you'll have the 404 response code. However I tested this example with App Engine and works as intended. I was able to serve all by index.html without getting 404. App engine has a free tier so you can take a look at it. https://cloud.google.com/free/docs/always-free-usage-limits#gae_name – Federico Panunzio Apr 11 '18 at 12:20
  • @MattDodge we are currently experiencing similar problems. Just curious, how did you end up solving this problem eventually? Thanks – Tim May 19 '19 at 19:34
  • 8
    @TimurMamedov I ended up just using AWS S3 haha – Matt Dodge May 20 '19 at 17:31
2

One way to circumvent the problem is to use server-side rendering. In SSR all client requests are passed to a backend app so there's no need for a Cloud Storage-hosted index.html.

This of course comes with its own set of complications but we're avoiding the above-mentioned 404 hack or resorting to any further dependencies like App Engine.

Alternatively you could go with hash-based routing, i.e. paths like https://example.com/#some-path.

Aleksi
  • 4,483
  • 33
  • 45
2

A very simple solution would be to just add the index.html file as the 404 fallback. This will always route everything to your single page app. enter image description here

Jobse
  • 166
  • 1
  • 13
-1

If you use Cloudflare, you can use a Cloudflare Worker to override the 404 status code, which comes from the Google Cloud Storage error page.

The code for the Worker should look like this:

addEventListener('fetch', event => {
    event.respondWith(fetchAndLog(event.request))
})

async function fetchAndLog(req) {
    const res = await fetch(req)
    console.log('req', res.status, req.url)

    if (res.status === 404 && req.method === 'GET') {
        console.log('overwrite status', req.url)
        return new Response(res.body, {
            headers: res.headers,
            status: 200
        })
    }
    return res
}

I found it here in the Cloudflare community.

stefan
  • 4,958
  • 4
  • 20
  • 37