mika
mika

Reputation: 65

Firebase rewrites problem with custom 404

Really new to firebase and very junior level at code. I am trying to figure out a bug where a custom 404 is not showing, or when rewrites changed then app does not work.

"rewrites": [
      {
        "source": "**",
        "function": "app"
      }
    ]

This redirects everything to the app and app functions properly. However, the 404.html doesn't show if a bad URL is attempted. There is a generic "Cannot GET /asdfasd"

Changed it to

"rewrites": [
      {
        "source": "/",
        "function": "app"
      }
    ]

This will now show the custom 404.html properly.

However, with this a function responds with 404 with this configuration, breaking the app. From functions/index.js:

app.post('/sendsmstoconsumer', (request, response) => {
    client.messages
      .create({body: request.body.message, from: '+15555555555', to: request.body.phone})
    .then(message => {
        response.send("Your message: " + request.body.message + " has been sent!")
    });
})

I have tried a number of variations like below, but I'm just missing something.

      {
        "source": "/",
        "function": "app"
      },
      {
        "source": "/sendsmstoconsumer",
        "function": "sms"
      }
    ]

change functions/index.js:

exports.sms = functions.httpsOnRequest((request, response) => {
    client.messages
      .create({body: request.body.message, from: '+15555555555', to: request.body.phone})
    .then(message => {
        response.send("Your message: " + request.body.message + " has been sent!")
    });
})

I would appreciate any help with the proper way to structure the rewrite, or change the function both the custom 404 and app work properly. I seem stuck with getting either one or the other.

Thank you.

As requested, editing to add the complete files:

firebase.json

{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "app"
      }
    ]
  },
  "emulators": {
    "functions": {
      "port": 5001
    },
    "database": {
      "port": 9000
    },
    "hosting": {
      "port": 5000
    },
    "ui": {
      "enabled": true
    }
  }
}

index.js

const functions = require('firebase-functions')
const express = require('express')
const app = express()
const accountSid = 'xxx'
const authToken = 'xxx'
const client = require('twilio')(accountSid, authToken)
const cors = require('cors')

// Enable cors for everything
// TODO: Re-enable cors at a later date 
// src: https://www.npmjs.com/package/cors
app.use(cors())

app.post('/sendsmsverificationmessage', (request, response) => {
    client.verify.services('xxx')
        .verifications
        .create({to: request.body.phone, channel: 'sms'})
    .then(verification => {
        response.send("Your verification code has been sent to your phone!" )
    });
})

app.post('/verifyusersphonenumber',  (request, response) => {
    client.verify.services('xxx')
        .verificationChecks
        .create({to: request.body.phone, code: request.body.token})
    .then(verification_check => {
        response.send("Your phone has been verified!")
        
    });
})

app.post('/sendsmstoconsumer', (request, response) => {
    client.messages
      .create({body: request.body.message, from: '+15555555555', to: request.body.phone})
    .then(message => {
        response.send("Your message: " + request.body.message + " has been sent!")
    });
})

exports.app = functions.https.onRequest(app)

Upvotes: 0

Views: 570

Answers (2)

mika
mika

Reputation: 65

Thanks to Michael Bleigh's answer, we found a solution, but had to specify the 404.html file.

app.use((req, res) => {
    res.set('X-Cascade', 'PASS')
    res.status(404).redirect('404.html')

})

Upvotes: 1

Michael Bleigh
Michael Bleigh

Reputation: 26333

By default a rewrite does not "fall through" once matched, so the response sent by the Cloud Function will always be returned directly to the user. There is actually a way to get around this: if your response body includes a header of X-Cascade: PASS.

In this case, Firebase Hosting will fall through to the default 404 behavior (including a custom 404.html). You should be able to add this to your Express app like so:

// *AFTER* all other endpoints
app.use((req, res) => {
  res.set('X-Cascade', 'PASS');
  res.status(404).send('Not Found');
});

Upvotes: 1

Related Questions