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)
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');
});
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')
})
Related
For a project I have the following url:
https://beterbijons.nl/belevingsapp/?name=Natuurleerpad
The website is made with NextJS, when I test this locally I had to add the following code:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
env: {
BASE_URL: process.env.BASE_URL,
},
trailingSlash: true,
images: {
loader: 'akamai',
path: '',
},
async redirects() {
return [
{
source: '/belevingsapp/',
has: [
{
type: 'query',
key: 'name',
value: '(?<paramName>.*)'
},
],
destination: '/belevingsapp/natuurleerpad-schipperskerk',
permanent: true,
},
]
},
}
module.exports = nextConfig
my firebase.json looks like:
{
"hosting": {
"public": "out",
"target": "productie-frontend",
"ignore": [
".firebase/**",
".firebaserc",
"firebase.json",
"**/node_modules/**"
],
"redirects": [ {
"regex": "/belevingsapp/?name=(.*)",
"destination": "/belevingsapp/natuurleerpad-schipperskerk",
"type": 301
}
]
}
}
This works. Only when I publish it to firebase hosting do I get a 'page not found' page, does anyone have a solution for this? The given url with ? I can't adjust..
We're using Firebase Hosting. We have a Next.js app, called "knowledge", deployed on Google Cloud Run in the same GCP project. We followed the instructions in the Firebase documentation. Our firebase.json is as follows:
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/knowledge{,/**}",
"run": {
"serviceId": "knowledge",
"region": "us-central1"
}
},
{
"source": "**",
"destination": "/index.html"
}
]
}
}
We want every request to "/knowledge{,/**}" for server-side rendering through our Next.js app on Cloud Run. When we open any of these pages, it loaded, but it does not load any of the static file, showing many errors like the following in the console:
Uncaught SyntaxError: Unexpected token '<' (at webpack-df4cf1c8d23aa877.js:1:1)
framework-81da43a8dcd978d9.js:1
Our next.config.js is as follows:
module.exports = {
async rewrite() {
return [
{
source: "/knowledge",
destination: "/",
},
];
},
images: {
domains: ["firebasestorage.googleapis.com"],
},
};
Static files will be under /_next/, so add '/path*'.
module.exports = {
async rewrite() {
return [
{
source: "/knowledge",
destination: "/",
},
{
source: "/knowledge/:path*",
destination: "/:path*",
},
];
},
images: {
domains: ["firebasestorage.googleapis.com"],
},
};
I have a firebase project with hosting for the frontend and a cloud function to handle all the backend requests. When I do firebase serve, and run the project on localhost, everything is fine. But, after deployment, when I try to access it online I get the following error.
Access to XMLHttpRequest has been blocked by CORS policy: Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
I have tried all the solutions for enabling CORS in firebase, but the error just doesn't disappear. What is causing this error and what can I do?
Relevant code in app.js (index.js equivalent) for cloud function
const functions = require('firebase-functions');
var express = require('express');
var cors = require("cors");
// These contain all the POSTS for the backend
var routes = require('./server/routes/routes');
var api = require('./server/routes/api');
var app = express();
app.use('/routes', routes);
app.use('/api', api);
app.use(cors({ origin: true }));
exports.app = functions.region('europe-west2').https.onRequest(app);
firebase.json
{
"hosting": {
"public": "public/client/dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/api/**",
"function": "app"
},
{
"source": "/routes/**",
"function": "app"
},
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
},
{
"source":
"**/*.#(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=604800"
}
]
}
]
}
}
Cross-origin resource sharing (CORS) allows AJAX requests to skip the Same-origin policy and access resources from remote hosts.
The * wildcard allows access from any origin
app.use(cors({
origin: '*'
}));
If you want to restrict AJAX access to a single origin, you can use the origin
app.use(cors({
origin: 'http://yourapp.com'
}));
To enable HTTP cookies over CORS
app.use(cors({
credentials: true,
origin: '*'
}));
OR
app.use(cors({
credentials: true,
origin: 'http://yourapp.com'
}));
I'm starting with Firebase and trying to implement an api but I'm having trouble trying to create some routes using Express. Follow:
firebase.json
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/api/**",
"function": "api"
},{
"source": "/api/auth/**",
"function": "api"
}]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
}
}
index.js
const functions = require("firebase-functions");
const cors = require("cors");
const express = require("express");
const api = express();
api.use(cors({ origin: true }))
api.use("/auth", require("./routes/auth"));
exports.api = functions.https.onRequest(api);
routes/auth.js
var express = require("express");
module.exports = () => {
var auth = express.Router();
auth.post("/signin", (request, response) => {
var service = require("../services/auth/signin");
service(request, response);
});
return auth;
}
services/auth/signin.js
module.exports = (request, response) => {
response.status(200).send({
"success": true,
"request": request.body.email
});
}
I'm not sure if it's the best framework and if the modules are implemented properly. Any suggestions are very welcome. Thank you!
for endpoint to be /api/auth/signin try
api.use("/api", require("./routes/auth"));
and
auth.post("/auth/signin", (request, response) => {
then remove
,{
"source": "/api/auth/**",
"function": "api"
}
a little counter intuitive in that it seems to be mapping /api twice, but this is working for me in several apps
My domain seems to redirect to the index.html and all the sub-links just fine.
Problem is it won't redirect to the api rule "source": "/api/**"
I've checked the API manually using the whole firebase url (no custom domain) and it works.
How can I get both domain.com/somelink and domain.com/api/somelink to work in union?
Here's the configuration.
firebase.json
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/api/**",
"function": "api"
},
{
"source": "**",
"destination": "/index.html"
}
]
},
"storage": {
"rules": "storage.rules"
}
}
As noted here https://stackoverflow.com/questions/44959652/firebase-hosting-with-dynamic-cloud-functions-rewrites/45224176#45224176
Create a main app which hosts all other top-level functions.
const funtions = require('firebase-functions');
const express = require('express');
const app = express();
app.get('/users/:userId/:userData/json', (req, res) => {
// Do App stuff here
}
// A couple more app.get in the same format
// Create "main" function to host all other top-level functions
const main = express();
main.use('/api', app);
exports.main = functions.https.onRequest(main);
firebase.json
{
"source": "/api/**", // "**" ensures we include paths such as "/api/users/:userId"
"function": "main"
}
Use the main hook.
const hooks = express();
main.use('/hooks/, hooks);