I have a route for '/' but it serves the public html index file instead, I tried changing the root directory of my api to /api/** but it gives me a 404 error.
it works quiet well when I run it locally but when I deploy it I run into the issue of only having the index.html file.
here is the firebase.json file
{
"hosting": {
"public": "public",
"rewrites":[
{
"source":"/api/**",
"functions":"app"
}
],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
and the index.js folder
const functions = require('firebase-functions')
const express = require('express')
\\.
\\.
\\requiring routes and middleware
app.use(helmet())
app.use(express.json())
app.use(cookieParser())
app.use(cors({
origin:"*",
credentials:true
}))
app.get('/',(req,res)=>{
res.status(200).send("works");
})
app.use(locationActions)
app.use(filterActions)
app.use('/auth',userAuth)
app.use('/adm',AdminRoutes)
app.use('/prod',prodActions)
app.use('/user',userActions)
exports.app = functions.https.onRequest(app);
.send() doesn't seem to work quiet well with firebase I just have to say something like response.json({message}), this will actually send the response. also mongoose connection is prohibited as I was using a free account so any connection outside firebase is rejected.
Related
I'm using Firebase Functions, and Firebase Hosting. Hosting redirects all traffic to my function.
Request cookies are not available when requesting the Hosted site (i.e. not the cloud function URL). Is there no way to access request cookies?
I'm migrating a website to Firebase and was assuming I could follow basic web principals of having access to same-domain cookies.
const { runWith } = require('firebase-functions');
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cookieParser());
function handleRequest(req, res) {
res.cookie('firebase1', 'test', {});
if (process.env.HOSTNAME) {
res.cookie('firebase2', 'test', {
domain: process.env.HOSTNAME,
});
}
res.cookie('firebase3', 'test', {
domain: req.hostname,
});
return res.json({
hostname: process.env.HOSTNAME,
'req.cookies': req.cookies, // always empty
'req.headers.cookie': req.headers.cookie, // always undefined
});
}
app.get('*', handleRequest);
app.use(handleRequest);
exports.index = runWith({
timeoutSeconds: 10,
memory: '128MB',
}).https.onRequest(app);
firebase.json
{
"functions": {
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log"
]
},
"hosting": {
"public": "public",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"function": "index"
}
]
}
}
Answer from Firebase's support team:
When using Firebase Hosting together with Cloud Functions or Cloud Run, cookies are generally stripped from incoming requests. This is necessary to allow for efficient CDN cache behavior. Only the specially-named __session cookie is permitted to pass through to the execution of your app.
When present, the __session cookie is automatically made a part of the cache key, meaning that it's impossible for two users with different cookies to receive the other's cached response. Only use the __session cookie if your app serves different content depending on user authorization. Also, you need to set the Cache-Control Header as private res.setHeader('Cache-Control', 'private').
I haven't tested it but the Express API doc indicates that, since you use the cookie-parser middleware, you should do req.cookies and not req.headers.cookie
I've implemented an express server that uses express.static to serve the build folder created from a static docusaurus site in order to apply basic authentication to access the site. This is working great locally, but I'm running into troubles when deploying to Vercel.
Currently my configuration is allowing the deployed version on vercel to render the basic auth login page, but upon successful login I am directed to a page the states: "Cannot GET /"
I belive this is likely an issue with either my vercel.json configuration, or with my vercel's template settings.
My code is as follows:
index.mjs
import express from 'express';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
app.use(express.json());
const authorize = ((req, res, next) => {
const auth = {login: process.env.USERNAME, password: process.env.PASSWORD}
const b64auth = (req.headers.authorization || '').split(' ')[1] || ''
const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':')
if (login && password && login === auth.login && password === auth.password) {
return next()
}
res.set('WWW-Authenticate', 'Basic realm="401"')
res.status(401).send('Authentication required.')
});
app.use('/', authorize);
app.use('/', express.static('build'));
app.listen(3000);
console.log(`🚀 Server ready at http://localhost:3000`);
vercel.json
{
"version": 2,
"builds": [{
"src": "./index.mjs",
"use": "#vercel/node"
}],
"routes": [{"handle": "filesystem"},
{
"src": "/.*",
"dest": "/"
}
]
}
package.json - start script
"start": "node --experimental-modules index.mjs",
And my vercel template is set to other, with the start script set to npm start.
Any ideas would be greatly appreciated!
I had similar issue: serve some static content and use /api routes. All worked fine in local dev but throwed "Cannot GET/" in vercel.
My solution.
Build separately serverless and static content.
Route adjustements for /api calls and static content.
My final vercel.json:
{
"version": 2,
"builds": [
{
"src": "server.js",
"use": "#vercel/node"
},
{
"src": "public/**",
"use": "#vercel/static"
}
],
"routes":[
{
"src": "/api/(.*)",
"dest": "server.js"
},
{
"src": "/",
"dest": "public/index.html"
},
{
"src": "/(.+)",
"dest": "public/$1"
}
]
}
Notes
All static content is under /public (html,css,img,js,etc)
server.js is the main app: express and route definitions. Similar to yours.
vercel build log shows:
Generated build outputs:
12:28:55.974 - Static files: 12
12:28:55.974 - Serverless Functions: 1
12:28:55.975 - Edge Functions: 0
...
12:28:58.142 Done with "server.js"
Maybe from this point you can find a solution for your case.
Ok, I've been looking for a solution for this one a little, and turns out we have to serve index.html explicitly in express:
app.get('/', (req: Request, res: Response) => {
res.sendFile('index.html', {root: path.join(__dirname, 'public')});
});
given that you probably have index.html in public folder. That's what solved the issue for me.
I have built a react app webpage, i use node, express and react. I serve it within an ec2 ubuntu server with nginx, i also installed ssl and configured DNS but when I load the page, the first time it gives no problems, but when reloaded, i get this Server responded with 429 status code
The page is very simple itself, but stills failing and i can't solve the problem, i have read a lot of posts and blogs to fix it but none has worked (this only happens in production, in dev environment i get no error when running my node app).
Some of those said that you had to lazy load images and i did it, i have also tried loading components in timeout so requests are made every 1.5 seconds...
The main files that give me problems are the manifest.json and favicon.ico, they are accesible by url so i can't understand why (another 429 example).
Node server.js
Routes has nothing, just console logs
require('dotenv').config();
const express = require("express");
const app = express();
const path = require("path");
const cors = require("cors");
const allowedOrigins = [`http://localhost:${process.env.PORT}`];
var corsOptions = {
origin: function (origin, callback) {
if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
};
app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.static(path.join(__dirname, "/public")));
app.use("/", require("./routes/routes"));
app.get("*", (_, res) => res.redirect("/"))
app.listen(process.env.PORT, function () {
console.log(`Listening on port ${process.env.PORT}`);
});
App directory structure
This is my folders structure, public folder is the build that react script npm run build returns.
React app directory structure
Here you can see the structure, nothing special to what you get when run npx create-react-app. As you can see, there's a favicon.ico and manifest.json.
Manifest.json
{
"short_name": "Proximedica BajÃo",
"name": "Proximedica BajÃo - OxÃgeno Medicinal",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
This is all, if you need me to provide some other file it would be a pleasure.
Thanks!
I created an Express app using Firebase Functions and am hosting the files on Firebase Hosting.
index.js (Firebase Functions):
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const parse = require('body-parser');
const cors = require('cors');
admin.initializeApp();
const app = express();
app.use(cors({ origin: true }));
app.use(parse.json());
app.use(parse.urlencoded({ extended: false }));
app.post('/create-url', (req, res) => {
console.log(req.body);
res.send(req.body);
});
exports.app = functions.https.onRequest(app);
firebase.json:
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "app"
}
]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"hosting": {
"port": 5000
},
"ui": {
"enabled": true,
"port": 4000
}
}
}
When I make an HTTP request to http://localhost:5000/create-url, req.body is emtpy, but when I make a request to http://localhost:5001/PROJECT_NAME_HERE/us-central1/app/create-url (I've hidden the project name), it works properly. I'm using Postman to make the requests, but it isn't working with my front-end code either :(. If I deploy to Hosting and Functions and access the app through the web.app domain, it works. I'm running firebase emulators:start to run locally.
Thanks in advance for your help!
Check out the bottom section of this page https://firebase.google.com/docs/emulator-suite/install_and_configure. 'Generate an auth token (Hosting emulator only)'.
Basically you have to generate an auth token and pass it as a flag in your build script or add it to your ci environment variables.
Let me know if it helps!
This is my first time deploying a VueJS app. It is full stack, back end is Express/MySQL. All running fine in developer mode. My dev platform is Windows 10, VS Code.
I am currently trying to preview the app on my dev PC using local webserver.
To that end, I built Vue app to server/public. The static site then runs fine, but I can't seem to get the Express back end to respond, either from the app or from browser accessing the api directly. I followed a model from Brad Traversy tutorial, here is what vue.config.js looks like:
const path = require('path');
module.exports = {
outputDir: path.resolve(__dirname, './server/public'),
devServer: {
disableHostCheck: true,
proxy: {
'/api': {
target: 'http://localhost:5000'
}
}
},
transpileDependencies: ['vuetify'],
pluginOptions: {
i18n: {
locale: 'en',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: false,
},
},
};
Here is the index.js for Express/back end. I commented out the NODE_ENV test because I haven't yet figured out how to set it properly. This should just hardwire the code to run in production mode. __dirname points to the server directory, which contains the Express code and other server stuff.
// Create express app
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
//Create Express App
const app = express();
// Add Middleware
app.use(bodyParser.json());
app.use(cors());
//
const water = require('./routes/api/water');
const waterlog = require('./routes/api/waterlog');
// Direct /api
app.use('/api/water', water);
app.use('/api/waterlog', waterlog);
// Handle production
// if (process.env.NODE_ENV === 'production') {
// Static folder
app.use(express.static(__dirname + '/public/'));
// Handle SPA
app.get(/.*/, (req, res) => res.sendFile(__dirname + '/public/index.html'));
// }
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`CORS-EnabledServer started on port ${port}`));
I use (from npm serve) this to start the Vue app:
serve -s server/public
What am I missing? Feels very close but no cigar yet...
serve is just a simple, static HTTP server. It won't run your backend.
Your production build puts your front-end assets into your Express app's statically served directory so all you should need to do after building the front-end is start your server
# Build your front-end
npm run build
# Start your Express server, assuming this is configured in package.json
NODE_ENV=production npm start
Now open http://localhost:5000/ in your browser
See also https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production