hope you are well!
I have an issue when trying to serve a create-react-app using an express.js server with Node.js backend.
For backend I have some routes defined to create an API with express and prisma, connecting to a database.
For frontend I used a react based app, Axios to fetch data from backend and react-router-dom V6 for client routing (BrowserRouter). To serve the files I created a build folder from React (in the .env file I have INLINE_RUNTIME_CHUNK set to false) with the npm run build script.
The files are generated correctly for the build and from the express app I attach these interface files with the separate route along with the API routes I have already defined. Everything goes okay, the interface opens, the API works but only if I navigate using components in the interface.
When I refresh a page in the browser, the application suddenly stops rendering, under a white screen. In the console area, in DevTools all kinds of loading errors appear which I will attach below with a print screen. The same thing happens if I try to navigate to another route in the browser bar.
I want to launch the application with express on an IP from a local machine. The server code is attached below with the required routes and middleware. So is the axios code and the routing in the interface. Has anyone else had problems like this?
import axios from 'axios';
const publicFetch = axios.create({
baseURL: "http://ABC.ABC.0.ABC:3002/api-v1"
});
export default publicFetch;
An this is the server code:
'use strict';
require('dotenv').config();
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const helmet = require('helmet');
const cors = require('cors');
const compression = require('compression');
const SERVER_PORT = process.env.SERVER_PORT;
// ================================================
// Server routes/controllers
// ================================================
const { createUser, getAllUsers, getSingleUser, updateUser, deleteUser, loginUser } = require('./routes/user-routes');
const { createDepartment, getAllDepartments, getSingleDepartment, updateDepartmentData, deleteDepartment } = require('./routes/department-routes');
const whitelist = ['ABC.ABC.0.ABC'];
const corsOptions = {
origin: function (origin, callback) {
if (!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
// ================================================
// Express App
// ================================================
const app = express();
app.enable('trust proxy');
// CORS
app.use(cors(corsOptions));
// JSON
app.use(express.json());
// ================================================
// static serve from server and client build
// ================================================
app.use(express.static(path.join(__dirname, '../client/build')));
// compress responses
// use compressions middleware for static files and res send
app.use(compression());
// ================================================
// Middleware
// ================================================
// morgan logs middleware
app.use(morgan('dev'));
// helmet security headers
app.use(helmet());
// disable Express mention in reasponse header
app.disable('x-powered-by');
// ===============================================
// User Endpoints
// ================================================
app.post('/api-v1/user', createUser);
app.get('/api-v1/user', getAllUsers);
app.get('/api-v1/user/:id', getSingleUser);
app.put('/api-v1/user/:id', updateUser);
app.delete('/api-v1/user/:id', deleteUser);
app.post('/api-v1/user/login', loginUser);
// ================================================
// Department Endpoints
// ================================================
app.post('/api-v1/department', createDepartment);
app.get('/api-v1/department', getAllDepartments);
app.get('/api-v1/department/:id', getSingleDepartment);
app.put('/api-v1/department/:id', updateDepartmentData);
app.delete('/api-v1/department/:id', deleteDepartment);
// Handles any requests that don't match the ones above
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../client/build/index.html'));
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../client/build/index.html'));
});
// ================================================
// Server start
// ================================================
app.listen(SERVER_PORT, "ABC.ABC.0.ABC", () => {
console.log(`Server running and listening on port ${SERVER_PORT}...`);
});
The errors that I get:
error in console
Related
Trying to set up my Express server on HTTPS but unable to access my api. Here is my code:
// server.js
const express = require('express');
const { readFileSync } = require('fs');
const https = require('https');
const app = express();
const key = readFileSync(
'/etc/letsencrypt/live/mydomain.com/privkey.pem',
'utf8'
);
const cert = readFileSync(
'/etc/letsencrypt/live/mydomain.com/fullchain.pem',
'utf8'
);
const ca = readFileSync(
'/etc/letsencrypt/live/mydomain.com/chain.pem',
'utf8'
);
const credentials = { key, cert, ca };
const port = 443
const server = https.createServer(credentials, app);
server.listen(port, () => console.log(`Server is running on port ${port}`));
The error I am receiving is a 502 Bad gateway on all calls to the server.
Everything worked perfectly before when I was running on HTTP like this:
const server = app.listen(8000, () => {});
Beside the URL on my site I can see the padlock icon and it says my site is secure so I believe my certifcate is valid.
Have seen a lot of similar questions posted on here and followed what I've seen in responses. I've even asked chatGPT to check my code and it doesn't see any errors. I've also tried reading my SSL keys as .env variables so I don't think the issue is an incorrect file path.
Can anybody please help me find the solution?
EDIT
Here is an example of a get request I am making to my backend using axios:
const fetchMembers = async () => {
await axios
.get(`/api/total-users`)
};
This invokes a function totalUsers with express.Router from a users file in my routes folder on the backend:
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/total-users', totalUsers);
const totalUsers = async (req, res) => {
try {
const total = await User.find().estimatedDocumentCount();
res.json(total);
} catch (err) {
console.log(err);
}
};
I am using a middleware app.use with a prefix /api and importing the users file to make a connection to my endpoints:
// server.js
const userRoutes = require('./routes/users')
app.use('/api', userRoutes)
While editing this question I tried modifying the middleware prefix to `:443/api' however this still hasn't helped.
Where is User defined inside of routes/users.js? You need to import your DB models before accessing them like this:
const total = await User.find().estimatedDocumentCount();
Otherwise, generally when running fetch('/api...), React will try to access localhost:3000/api instead of localhost:443/api.
React needs to know where to proxy requests to the backend. One way is using the http-proxy-middleware library and by defining a setupProxy.js file.
client/src/setupProxy.js
/**
* Proxy most calls to the server
* #type {Array}
*/
/* eslint-disable #typescript-eslint/no-var-requires */
const { createProxyMiddleware } = require('http-proxy-middleware');
const proxy_urls = ['/api/*';
const target = 'https://localhost:443';
module.exports = function (app) {
proxy_urls.forEach((url) => {
app.use(url, createProxyMiddleware({ target }));
});
};
I'm a bit of a JS and Vue noob and I'm trying to figure out how to run my Vue app and a websocket server for that app on the same port 80 (to later be put behind a reverse proxy). I am able to get this working as a simple http server with express, but I can't figure out how to do it with my Vue use case.
My goal is to run a single main.js with npm run serve and bind the websocket server and routes I'm setting up with the vue router all in one application, on the same port.
Here is the example for the simple HTTP case:
server.js
'use strict';
let fs = require('fs');
let express = require('express');
let app = express();
let bodyParser = require('body-parser');
let WSServer = require('ws').Server;
let server = require('http').createServer();
let PORT = 8080
app.use(bodyParser.json());
// regular HTTP request and response
app.get('/', function(req, res) {
console.log('Get index');
fs.createReadStream('./index.html').pipe(res);
});
app.post('/', function(req, res) {
let message = req.body.message;
console.log('Regular POST message: ', message);
return res.json({ answer: 42 });
});
module.exports = app;
// Create web socket server on top of a regular http server
let wss = new WSServer({ server: server });
// Also mount the app here
server.on('request', app);
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log(`received: ${message}`);
ws.send(JSON.stringify({ answer: 42 }));
});
});
server.listen(PORT, function() {
console.log(`http/ws server listening on ${PORT}`);
});
But my question is how can I modify the default main.js vue file to do this?
import { createApp } from 'vue';
import App from './App.vue';
---
import router from './router';
import store from './store';
createApp(App).use(store).use(router).mount('#app');
is there any way to make the node.js server update automatically with the new certificates generated by let's encrypt every 3 months without restarting the service?
My server has a hosting panel that auto manages the certificates, so I can't use the certbot manually.
Currently I have a cron that runs monthly and restarts the server to take the new changes, but sometimes the certificate changes a few days before and my sites and apis stop working until my server restarts. It doesn't seem to me the most optimal solution.
const fs = require("fs");
const https = require("https");
const express = require("express");
const helmet = require("helmet");
var cors = require("cors");
const API = require("./index.js");
const hostname = "ENV.HOSTAME";
const httpsPort = ENV.PORT;
const httpsOptions = {
cert: fs.readFileSync("CERT-PATH"),
ca: fs.readFileSync("CA-PATH"),
key: fs.readFileSync("CA-KEY"),
};
const app = express();
app.use(helmet());
app.use(cors());
const httpsServer = https.createServer(httpsOptions, app);
// Parse URL-encoded bodies (as sent by HTML forms)
//app.use(express.urlencoded());
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.get("/", function (req, res) {
res.redirect("HOSTNAME");
});
app.post("API-ROUTE", async function (req, res) {
const response = await API(req);
if (response != "Error") {
res.status(200).send(response);
} else {
res.status(500).json({ message: "Server Error" });
}
});
httpsServer.listen(httpsPort, hostname);
nodejs uses http service and nginx for reverse proxy. When the certificate is updated, there is no need to restart the whole service. Executing nginx -s reload works for me.
I want to create a hidden internal webserver with ever-changing routes.
The aim is to prevent/deter people from scraping the site or using the API without permission.
There's probably a better way (or this could be totally useless)
I've written some code that works but either convince me why I'm wasting my time or why it would work.
const express = require('express');
const uuid = require('uuid/v4');
const app = express();
// These are the hidden routes
const routes = {
hiddenPage: undefined,
};
setInterval(() => {
// Change the path of the hidden page
// every 5 seconds
routes.hiddenPage = `/${uuid()}`;
}, 1000 * 5);
app.get('*', (req, res) => {
// There would be other middleware for
// security reasons
if (req.path === routes.hiddenPage) {
res.send('Welcome to the hidden page');
return;
}
res.send(`Page at <a href=${routes.hiddenPage}>${routes.hiddenPage}</a>`);
});
// Listen on 3000
app.listen(3000);
You can use CORS middleware to allow only specific clients to access your server.
https://expressjs.com/en/resources/middleware/cors.html
Example:
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://example.com',
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
I've been trying to understand how to set up Stripe for my app but am having problems with the implementation of the module. Normally when using a module i would require it in the top of the file to be able to use it but I'm not sure how to do this here in the paymentController file or if i even need to. I imported the Stripe npm, so does that i mean that i can access it globally? Well as you see i'm quite new to this and would like to understand how to structure this so that the payments work.
app.js file:
angular.module('userApp', ['appRoutes', 'userControllers', 'userServices', 'ngAnimate', 'mainController', 'authServices', 'managementController', 'paymentController'])
.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptors');
});
paymentController file:
angular.module('paymentController', [])
.controller('paymentCtrl', function($scope) {
var app = this;
});
Server.js file:
var express = require('express'); // ExperssJS Framework
var app = express(); // Invoke express to variable for use in application
var port = process.env.PORT || 8080; // Set default port or assign a port in enviornment
var morgan = require('morgan'); // Import Morgan Package
var mongoose = require('mongoose'); // HTTP request logger middleware for Node.js
var bodyParser = require('body-parser'); // Node.js body parsing middleware. Parses incoming request bodies in a middleware before your handlers, available under req.body.
var router = express.Router(); // Invoke the Express Router
var appRoutes = require('./app/routes/api')(router); // Import the application end points/API
var path = require('path'); // Import path module
var passport = require('passport'); // Express-compatible authentication middleware for Node.js.
var social = require('./app/passport/passport')(app, passport); // Import passport.js End Points/API
app.use(morgan('dev')); // Morgan Middleware
app.use(bodyParser.json()); // Body-parser middleware
app.use(bodyParser.urlencoded({ extended: true })); // For parsing application/x-www-form-urlencoded
app.use(express.static(__dirname + '/public')); // Allow front end to access public folder
app.use('/api', appRoutes); // Assign name to end points (e.g., '/api/management/', '/api/users' ,etc. )
mongoose.connect('mongodb://localhost:27017/tutorial', function(err) {
if (err) {
console.log('Not connected to the database: ' + err);
} else {
console.log('Successfully connected to MongoDB');
}
});
// Set Application Static Layout
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/index.html')); // Set index.html as layout
});
// Start Server
app.listen(port, function() {
console.log('Running the server on port ' + port); // Listen on configured port
});
I'd recommend following what's shown for Node in this Stripe tutorial:
https://stripe.com/docs/charges
Just like your other includes, you want something like this at the top of any JS file that will use the Stripe library:
var stripe = require('stripe')('sk_my_secret_key')
Then, elsewhere in the same file, you can call any Stripe library methods you need:
stripe.charges.create(…)
Of course, in production you'll want to build a proper 12 Factor app[1] and put your secrets in environment variables or configuration files.
[1] https://12factor.net/config