Implementing localized 404 page with Firebase hosting

后端 未结 2 1650
一生所求
一生所求 2020-12-04 02:57

Say my web app has two locales: English(myapp.com/en/) and French(myapp.com/fr/). I want to localize my 404 pages, so that request to myapp.c

2条回答
  •  悲&欢浪女
    2020-12-04 03:28

    This answer is outdated. Firebase now supports this functionality by default. See the correct answer.


    One way of achieving this functionality is by using rewrites:

    {
      ...
      "hosting": {
        "rewrites": [
          {
            "source": "/fr/**",
            "destination": "/fr/404.html"
          },
          {
            "source": "**",
            "destination": "/en/404.html"
          }
        ]
      }
    

    This will serve the /fr/404.html/ page for unmatched requests inside /fr/ directory and /en/404.html for any other unmatched request.

    The downside of this approach is that the returned status code is 200 instead of 404.


    A better solution is to rewrite unmatched requests to Cloud Functions that return the needed 404 page and the 404 status code. Note, that the 404 pages have to be located in functions/lib directory, not public.

    Also, with the use of proper Cache-Control header, you can allow the Firebase Hosting to cache the output of the Functions so that they don't have to run every time a 404 page is requested.

    Firebase config:

    {
      ...
      "hosting": {
        "rewrites": [
          {
            "source": "/fr/**",
            "function": "pageNotFoundFr"
          },
          {
            "source": "**",
            "function": "pageNotFound"
          }
        ]
      }
    

    The functions:

    exports.pageNotFound = functions.https.onRequest((req, res) => {
        res.set("Cache-Control", "public, max-age=31536000")
        res.status(404).sendFile("en/404.html", {root: __dirname})
    })
    
    exports.pageNotFoundFr = functions.https.onRequest((req, res) => {
        res.set("Cache-Control", "public, max-age=31536000")
        res.status(404).sendFile("fr/404.html", {root: __dirname})
    })
    

    But this approach duplicates the code and can be messy in case you have more languages.


    It would be better to extract the request handler into a function:

    exports.pageNotFound = functions.https.onRequest(notFoundHanler("en"))
    exports.pageNotFoundFr = functions.https.onRequest(notFoundHanler("fr"))
    
    function notFoundHandler(lang) {
        return function (req, res) {
            res.set("Cache-Control", "public, max-age=31536000")
            res.status(404).sendFile(`${lang}/404.html`, {root: __dirname})
        }
    }
    

    Update: I filed a feature request for multiple 404 pages to Firebase and they replied that it will be taken into consideration.

提交回复
热议问题