express.js cannot find route at reload after initial load - node.js

I created a small express server to serve my react app. It's a static context react app that only uses API calls to fetch and show data.
When I start my server everything goes well and when I navigate to localhost:5000 the server automatically redirects to localhost:5000/login. However, the server throws an error once the login page is loaded and I trigger a reload. It then gives me Error: Cannot GET /login.
Does anyone has an idea what goes wrong? Here is the code of my express server script which I trigger with yarn start (added start script in package.json ("start": "NODE_ENVIRONMENT=production node server.js").
const express = require("express");
const app = express(); // create express app
// add middleware
app.use(express.static("dist"));
// start express server on port 5000
app.listen(5000, () => {
console.log("server started on port 5000");
});

Related

Is it possible to directly connect ReactJs with ExpressJs?

My needs are simple, I want the ReactJs frontend served from an ExpressJs server, without crazy separate ports and stuff.
Is it possible to send HTTP requests to my server for APIs as well?
How can I do this?
Yes and yes.
You create the react site. Use the dev server to develope it and make it look nice. When its ready you build it by doing
npm run build
Then you create the express server and make it serve the static html files
const express = require('express')
const app = express()
app.use('/', express.static('dist'))
app.listen(3000, () => { console.log('running on 3000') })
Now you can open the express app on server 3000 and it serves the react site.

React app (via create-react-app) with Express backend in single Azure app?

I have a React front-end app with an express backend that's working locally as a proxy API server.
In my local dev environment, the React fonr-end is running on port 3001, with the Express server running on port 3000.
In my package.json, I have the proxy set up:
"proxy": "http://localhost:3000",...
The app is deployed via an Azure pipeline, which builds the app and the server, zips them up, and copies the artefacts to an Azure domain.
In the Azure app's Configuration, I have the following Startup Command:
node server & npx serve -s
This should (in theory) start the Express server (which is set to listen on port 3000) and server the front-end. The front-end is indeed accessible, but when it tries to make a call to the api via a simple fetch request, it's returning the HTML of the React app instead of a JSON response. This indicates to me that it's not actually exposing the Express port to the front end.
Is it actually possible to server the Express server and the frontend as part of the same container?
It turns out that this approach - while it was the wrong one - was in fact working, but Azure App Services will only expose a single port. In this case, we could either expose the React front end via npx serve -s OR expose the api by setting the PORT variable to 3000. Both were running, but only one could be reachable.
The solution was to serve the React front-end via the Express server:
const path = require('path');
const { response } = require('express');
const express = require('express');
const request = require('request');
const app = express();
app.use(express.json());
app.use(express.static(path.join(__dirname, '../')));
app.use('/api', function (req, res, next) {
// API function calls here
...
});
app.get('*', function(req, res, next) {
res.sendFile(path.join(__dirname, '../index.html'));
});
app.set('port', 3000);
app.listen(app.get('port'), () => {
console.log('Proxy server listening on port ' + app.get('port'));
});
And set the PORT container variable to 3000.

Nuxt.js get status 400 from express API on production mode

I develop an app with Nuxt and Express API on my local mashine. Here is all working fine.
Its a sigle Nuxt app with axios. The Express API is single too.
Now I put the API and Nuxt app on my server Ubuntu (Plesk). Now the API + Nuxt app is running, when I open Nuxt pages without asyncData or async fetch, it works also fine. But when I open (on reload) a page with the asyncData request I get an error:
Server error
An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.
This is working:
request from Postman to online API (status 200)
go on page without asyncData and click on the link without reload (no SSR)
This is not working:
SSR -> open direct URL to page with asyncData from API (In the server Logs give the API a status code 400)
Here is my short testing code:
Express
const express = require('express')
const app = express()
const port = process.env.PORT || 5555
const cors = require('cors')
app.use(cors())
app.get('/public', (req, res) => {
res.send('response')
})
app.listen(port)
Nuxt.js
asyncData ({ $axios }) {
return $axios.$get(`https://api.domain.com/public`)
.then((res) => {
return { data: res }
})
}
the funny thing is that when I make a request to (https://jsonplaceholder.typicode.com/todos) the asyncData is working. Thats why I think it is a problem in my API

Using Mixpanel - Node Library in Express

I am currently trying integrate the Mixpanel Node library into a test application that I am building. This is a Node.js application using the express framework.
As per the express docs, I have a JS file to manage the project, a folder called "public" that contains all of my static files, and another folder with the node modules that come with express.
I have two static HTML pages in "public" that I am trying to put mixpanel tracking into. I am running the project locally by running node app.js.
app.js includes:
const express = require('express');
const app = express();
const port = 3000;
const path = require('path');
//Mixpanel Additions
var Mixpanel = require('mixpanel');
var mixpanel = Mixpanel.init('<I am putting my project token here>', {
protocol: 'https'
});
//App Configuration and Init
app.use(express.static('public'));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/public/page.html'));
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
In my HTML files I try to use mixpanel functions by putting them into script tags:
<script>
mixpanel.track("event")
</script>
But when I run node app.js and view the page in my browser it says:
Uncaught ReferenceError: mixpanel is not defined
I have a pretty poor understanding of node.js, but I am imagining that I need to use app.use(), app.get(), or something along those lines to get the Mixpanel lib loaded into the app. What am I doing wrong? I also realize that my understanding of Express and Node is pretty rudimentary, so any additional knowledge is appreciated, especially if I am way off.
If you want to call mixpanel tracking functions in the browser, you should load the mixpanel library in a script tag on the browser side, as seen here:
https://developer.mixpanel.com/docs/javascript
The purpose of the node.js package is to send events from the server side, like if you wanted to log when page.html is rendered, you could do
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/public/page.html'));
mixpanel.track('event')
});

Heroku node + react app: anchor tag auth request unhandled

I'm building a node + express server, with create-react-app to the frontend.
I used passportjs for auth routes handling, and all the stuff totally working on localhost ( backend on port 5000 and frontend on port 3000, with a proxy ).
When I deploy to Heroku, seems like the server can't recognize my auth routes and so heroku serve up static index.html.
If I test my APIs with Postman all seems to work ( I can see the html page for google oauth ), but with an anchor tag in my react app or manually writing the endpoint in the url, I can see only the same page reloading.
My server index.js:
const express = require('express')
const passport = require('passport')
const mongoose = require('mongoose')
const path = require('path')
// KEYS
const keys = require('./config/keys')
// MONGOOSE MODELS
require('./models/User')
mongoose.connect(keys.mongoURI)
// PASSPORT SETUP
require('./config/passport')
// CREATE THE SERVER
const app = express()
// EXTERNAL MIDDLEWARES
require('./middlewares/external')(app)
// ROUTE HANDLERS
require('./routes/authRoutes')(app)
// PRODUCTION SETUP
if (process.env.NODE_ENV === 'production') {
// express serve up production assets ( main.js, main.css )
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// START THE SERVER
const PORT = process.env.PORT || 5000
app.listen(PORT)
Flow:
LOCALHOST:
react app starts -> I click 'Google Login' -> GET request to "/auth/google" -> google oauth flow -> redirect to "/" and my react app reappears, the user is logged in.
HEROKU:
react app on my-app.herokuapp.com/ -> click on "Google Login" -> the page reloads, nothing happens. the user is not logged in.
Please guys, help me.
Thanks
This is a result of the service worker being installed by default to make your app a Progressive Web App
To determine if this is an issue for you, test your heroku production mode app in incognito mode. The request for /auth/google should now reach the server and behave as it does in development.
Once you determine it is an issue, you can remove the
import registerServiceWorker from "./registerServiceWorker";
from your /client/src/index.js file.
You browser cache may already contain an installed service worker so you may have to
clear browser cache on a user browsers
uninstall the server worker programmatically
import { unregister } from './registerServiceWorker';
....
unregister();
I had the same issues with same symptoms exactly.
For me the cause was a typo in the keys: in server/config/prod.js I had a line reading cookieKey: process.env.COOKIE_KEY but in Heroku Config Variables that variable was named cookieKey. Renaming it to COOKIE_KEY inside Heroku solved the issue.
If you've followed the Stephen Grider tutorial one thing I'm wondering: Is your passport.js file in config or services? I see you've written in index.js: require('./config/passport')
whereas mine in index.js is require('./services/passport')
may not be your solution to the google oauth flow hanging in production but may help.

Resources