I am having trouble handling a (custom) 404 with Firebase Hosting and Functions. Below is a simplified code that works without issue on localhost.
However there seem to be an issue handling 404 when I deploy it. Firebase Hosting returns a 500 instead of 404.
https://xxxx.web.app/myfunction/hello
-> returns "hello world"https://xxxx.web.app/myfunction/404
-> returns 500 errorhttp://localhost/myfunction/404
-> returns (custom) 404Does anyone know what is wrong with this?
index.js
const functions = require('firebase-functions');
exports.myfunction = functions.region('asia-east1').runWith({maxInstances: 2}).https.onRequest((request, response) => {
if (request.path == '/myfunction/hello') {
return response.send("hello world")
}
response.set('X-Cascade', 'PASS');
return response.status(404).end()
});
firebase.json
{
"functions": [
{
"source": "functions",
"codebase": "default",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log"
]
}
],
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/myfunction/*",
"function": "myfunction",
"region": "asia-east1"
}
]
}
}
edit: The basic file structure is something like this:
.
├── firebase.json
├── functions
│ ├── index.js
│ └── package.json
└── public
├── 404.html
└── index.html
Firebase functions and firebase hosting run on completely different environments when in production, therefore the 404.html
file in the public
folder will only apply when the browser triggers a 404 Not Found error
, NOT a firebase function which is on the server side as seen from the documentation.
This is different when you are using the local emulator, because the functions emulator has access to the files, hence why it is working locally.
From your code, you have two options.
Option 1
You can create a custom 404.html
inside the functions
directory and send it to the browser as shown below.
NB: I have removed X-Cascade
because is not necessary and will cause a 500 error
as you described.
const functions = require('firebase-functions');
exports.myfunction = functions
.region('asia-east1')
.runWith({ maxInstances: 2 })
.https.onRequest((request, response) => {
if (request.path == '/myfunction/hello') {
return response.send('hello world');
}
return response.status(404).sendFile('404.html', { root: __dirname });
});
Option 2
A simpler way is to specify the route in your firebase.json
.
"hosting": {
"public": "public",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/myfunction/hello",
"function": "myfunction",
"region": "asia-east1"
}
],
},
Then in your cloud function:
const functions = require('firebase-functions');
exports.myfunction = functions
.region('asia-east1')
.runWith({ maxInstances: 2 })
.https.onRequest((request, response) => {
return response.send('hello world');
});