CANNOT GET / problem with React, Node Js and Express - node.js

I'm getting a problem opening up my app. I already built the app using create-react-app (nodejs and express on the backend) and it's "colorsofemre.com". When I'm trying to make changes in the app though, all I get is a CANNOT GET / error on the browser.
This is my server.js
const express = require('express')
const app = express()
port = process.env.PORT || 3000 ;
var bodyParser = require('body-parser')
var path = require("path")
app.use(bodyParser.json());
var cors = require('cors');
app.use(cors());
app.use('public', express.static(path.join(__dirname, 'src')));
app.use('public', express.static(path.join(__dirname, 'public')));
app.get('/color', async (req, res) => {
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) return console.log(err)
// Storing a reference to the database so you can use it later
db = client.db('ColorPicker')
db.collection('Colors').find({}).toArray((err,result)=>{
if(err) throw err;
console.log(result);
res.status(200).json(result)
console.log(result);
})
});
});
app.listen(port,()=>{console.log("Listening on port"+port)});
This is my client side fetch function the get /color.
async updateArray(){
this.colors=[];
const result = await fetch(`http://localhost:3000/color`,{mode: 'cors'});
const data = await result.json();
this.arrayModified(data);
this.setState({render:true});
}
When I enable the client side I get this error
Unhandled Rejection (SyntaxError): The string did not match the expected pattern.
21 |
22 | this.colors=[];
23 | const result = await fetch(`http://localhost:3000/color`,{mode: 'cors'});
> 24 | const data = await result.json();
| ^ 25 | this.arrayModified(data);
26 | this.setState({render:true});
27 | }
And if I comment the client side fetch code, I only get Cannot /GET on my browser. Database works fine and when I go to localhost:3000/color, json data is loaded perfectly.
My file structure is
-public
-index.html
-src
-index.js
-app.js
-and other js components
-server.js
I've been trying to figure out what's wrong for 2 days. Thank youu!

Try adding a catch-all route like this to your server.js, to redirect your GET requests to index.html first:
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})
Source: Fixing the "cannot GET /URL" error on refresh with React Router and Reach Router (or how client side routers work)

Related

Cannot post request to nodejs route on ECS but can locally (404 error)

I’ve been having an issue with deploying my nodejs App on AWS ECS Fargate. Running the app locally on my device with nodemon or building the app and running the build file is successful and I can ping my routes using postman. The issue happens when I deploy this same exact code on AWS; using postman, to do a POST request, I get a 404 error. Please note, I'm running a Node:14 container.
For reference, my nodejs code is structured in a way where there’s a main route.js file containing all routes, then there are specific route files, for example listingRoute.js, contains all the sub-routes then there are controllers (.js files) containing all the logic where I export the function and tie it with the route in the listingRoute.js example.
Here's what my main Route.js file looks like:
const express = require('express');
const error = require('../Middleware/error');
const listingRoute = require('../Routes/listingRoute');
module.exports = function (app) {
//Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false , limit : '20mb' }));
app.use('/listing', listingRoute);
//The final middleware to be called in case of an unhandled error.
app.use(error);
process.on('uncaughtException', function(err) {
// Handle the error safely
console.log(err)
})
};
My listingRoute file
const express = require("express");
const route = express.Router();
const listingController = require("../Controllers/listingController");
require('dotenv').config();
route.post("/create", listingController.createListing)
route.post("/update", listingController.updateListing)
route.post("/read", listingController.getListing)
route.post("/delete", listingController.deleteListing)
...
...
...
...
...
route.post("/getMostPopular" , listingController.getMostPopular)
route.post("/getByCategory" , listingController.getByCategory)
route.post("/getAllTOS" , TOSController.getTOSByListing)
route.post("/getTOS" , TOSController.getTOSByID)
route.post("/updateTOS" , TOSController.updateTOS)
route.post("/deleteTOS" , TOSController.deleteTOS)
route.post("/createTOS" , TOSController.createTOS)
route.post("/getListingsByIDs" , listingController.getListingsByIDs)
route.post("/cacheImagesNewCDN" , listingController.cacheImagesNewCDN)
module.exports = route;
My listingController file
const listingModel = require('../Models/listingModel');
const moment = require('moment')
const axios = require('axios');
var fs = require('fs');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
var fs = require('fs');
//tested
const createListing =async (req, res) => {
try {
//some logic here
}
catch (err) {
console.log(err)
return res.status(500).json({ error: err.message });
}
}
const updateListing = async (req, res) => {
try {
//some logic here
}
catch (err) {
return res.status(500).json({ error: err.message });
}
}
module.exports = {
getListing,
updateListing,
deleteListing,
createListing,
listingwithViews,
advertisedListings,
filterListings,
pressedOnBookNow,
cacheImages,
recommendListings,
getCacheMetaData,
addIndoorAmenity,
missingFromFilter,
adjustCreativeStudios,
listingsToCSV,
getAllListing,
getDiscountedListings,
addRevenueToListings,
getMostPopular,
getByCategory,
getListingsByIDs,
cacheImagesNewCDN,
getOwnersPhones
}
All the routes starting from getMostPopular till the end of the list give an error 404 not found although I have done the same procedure to all of them. Any ideas why this is happening? If you feel this isn't enough information to help diagnose, let me know and i'd be happy to provide more details. You're help would be beyond appreciated, thanks!

Axios Vue app only Post Request Network error

Using the Following Stack Express,Vue,SQL,Axios
GET request is working fine in postman as well from Axios
POST request created error in both attached screenshots
To make sure the Backend is working fine I have tried sending the Data directly from
<form action="url" method="POST">
it is Working fine and data is storing in the database
I have Tried few workaround like disabling SSL setting in postman and Played with proxy setting Also having CORS enabled in the backend and tried some Allow content and header things. Nothing worked
Not able to figure out the Problem in the POST Request. Please Help
--Request Error in the browser from Axios ----
Axios Browser Error
-postman Error when doing POST Request---
Postman Error
---Backend Index.js file---
// const express = require("express");
"use strict";
import express from "express";
const app = express();
import cors from "cors";
//listening on this port
app.listen(3000);
app.use(cors()); // to get Data from Other Domains
app.get("/", function (req, res) {
res.send("Application Started");
console.log("Application Started");
});
//Routes
app.use("/product", require("./routes/product"));
---product.js routes files---
import express from "express";
const router = express.Router();
import bodyParser from "body-parser";
//Middleware
router.use(bodyParser.urlencoded({ extended: true })); // To Parse the body data
//Importing Main Controller
import conProduct from "../controllers/ConProduct";
//Defining functions as per Routes
router.post("/add", conProduct.add); //Showing all the products
router.get("/get", conProduct.get); //Showing all the products
//Exporting Router
module.exports = router;
---Controller for Product file ConProducts.js ---
import sqlConfig from "../database/dbConfig";
let sql = sqlConfig.mysql_pool;
exports.add = (req, res) => {
console.log(req.body);
const { name, shortDescription, price, discount } = req.body;
let addQuery =
"INSERT INTO products(name,short_description,price,discount) VALUES('" +
name +
"','" +
shortDescription +
"','" +
price +
"','" +
discount +
"');";
sql.query(addQuery, (err, result) => {
if (err) throw err;
console.log(result);
res.send("product uploaded");
});
};
--Frontend axios Request --
let formData = {
name: this.name,
shortDescription: this.shortDescription,
price: this.price,
discount: this.discount,
};
console.log(formData);
axios
.post("/product/add", formData)
.then((res) => console.log(res))
.catch((error) => console.log(error));
I got the Answer I was missing a middleware app.use(bodyParser.json) in index.js and because of that there was no value going into database and thus, there was a network error.
I realized that, you are sending a PUT request to backend but your API controller receiving POST requests. So, Don't they have to be same type of request ?

Not getting expected results from included files in Nodejs

I'm not getting expected results by including files in Nodejs. Here is my code:
Service Route File
const express = require('express');
const router = express.Router();
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Main Server File
const express = require('express');
const userApiService = require('./routes/userService');
const userAdminService = require('./routes/userService');
app.use('/api/user_service/', userApiService("/api", config.userServiceUrl) );
app.use('/admin/user_service/', userAdminService("/admin", config.userServiceUrl) );
var server = app.listen(3000, function(){
console.log('Server listening on port 3000');
});
module.exports = server;
Expecting Console Result:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /admin (when hitting http://baseurl.com/admin/<anything>)
But Getting Console Output as:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /api (when hitting http://baseurl.com/admin/<anything>)
Both the time, returning /api path.
Can anyone tell me why is it happening and what's the solution?
You're creating only one router in userService.js (the first file). It's created once before the function so you really only end up with one router. The first time you require it the router gets created, but the second time you require it Node knows it was already loaded and it's not re-initialized. You should be creating a different router for each case like this:
const express = require('express');
// const router = express.Router(); <-- don't do it here
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
const router = express.Router(); // <--- create a new router for each case
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Also in your main server file you only need to require it once. It's just a function to create the service so you don't need 2 different variables holding that function. So you can initialize both using the one function like this:
// const userApiService = require('./routes/userService');
// const userAdminService = require('./routes/userService');
const service = require('./routes/userService');
app.use('/api/user_service/', service("/api", config.userServiceUrl) );
app.use('/admin/user_service/', service("/admin", config.userServiceUrl) );

NodeJS, Express. Cannot upload static content

I've tried to write node server which would run React app created by create-react-app. Actually, something strange happens and I don't have any clue what I'm doing wrong (run app as node server/index.js):
export default (app, dirname) => {
app.use(favicon(path.join(dirname, '..','build', 'favicon.ico')));
app.use(express.static(path.join(dirname, '..','build')));
// initialize routers
bootRotes(app);
if (process.env.NODE_ENV === AVAILABLE_ENVIROMENTS.DEVELOPMENT) {
expressBootDev(app, dirname);
} else {
app.get('/*', (req, res) => {
res.sendFile(path.join(dirname, '..', 'build', 'index.html'));
});
}
}
build folder contains build react app which created the following command npm run build
Strange things are happening when after uploading index page it tries to upload static content. For example http://localhost:5000/static/js/2.30e86b6e.chunk.js. Browser just adds / after each static content url and it turns to http://localhost:5000/static/js/2.30e86b6e.chunk.js/ and of course this url doesn't match to express.static middleware.
Moreover, I've checked via Postman, that url GET http://localhost:5000/static/js/2.30e86b6e.chunk.js withot / at the end provides content which is expected.
I work with PRODUCTION env, it means that expressBootDev doesn't have any impacts.
Has anybody has the same issue? I've spent whole day and don't know hopw to fix it.
When I'm creating a simple code in a root app folder with almost the same logic and run as node server.js and it works as expected:
//server.js
const express = require('express');
const favicon = require('express-favicon');
const path = require('path');
const port = process.env.PORT || 8080;
const app = express();
app.use(favicon(__dirname + '/build/favicon.ico'));
app.use(express.static(__dirname));
app.use(express.static(path.join(__dirname, 'build')));
app.get('/ping', function (req, res) {
return res.send('pong');
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(port);
And I don't see any principal difference
var fs = require('fs');
var express = require('express');
var router = express.Router();
// GET: Sent some basic info for usage
router.get('/', (req, res, next) => {
var fname = __dirname + '/../public/index.html';
var val = fs.readFile( fname, 'utf8', ( err, data) => {
//send can only be called once, write can be called many times,
// in short res.send(msg) == res.write(msg);res.end();
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(data);
res.end();
});
});
module.exports = router;
Here is the example how you can do a static file serving with node.
https://github.com/msatyan/ApiServe1/blob/master/routes/index.js
The full project is
https://github.com/msatyan/ApiServe1
FYI: Node.js with HTTP1 is not an efficient for static file serving by design, I believe HTTP2 support in node has addressed this problem. The reason for inefficiency with HTTP1 is that it has to take the file content read at native layer to JavaScript layer and then send it through HTTP server.

NodeJS + React + Next Framework adding a path to the route

I'm attempting to setup a NodeJS application that is using the Next framework to utilize client and server side rendering. I'm trying to get the client and server side rendering to prepend a path to the routes/URLs it generates. The server side render seems to be working by setting up the express server GET function to listen for requests made on route and then passing that along to node by stripping out the prepended route value. However when it comes the rendering on the client the prepended value is missing even when the as="{somestring}" is added to the .js pages for elements like Link so when the external Next javascript files are referenced in the render it's missing the prepended value.
The purpose for the routing is to allow us to run multiple micro-services on one domain each hosted on different instances in AWS and being routed using Target Groups and an ALB.
Essentially what I want to do is replace / with /{somestring} and I need this to be included not only in the server side rendering but in the client side rendering.
URL Example:
www.example.com -> www.example.com/somestring
HTML Render:
www.example.com/_next/960d7341-7e35-4ea7-baf6-c2e7d457f0db/page/_app.js -> www.example.com/somestring/_next/960d7341-7e35-4ea7-baf6-c2e7d457f0db/page/_app.js
Edit/Update
I've tried to use app.setAssetPrefix and while it renders the requests for the assets correctly and the pages load the assets themselves are 404ing.
Here is my server.js file:
const express = require('express');
const next = require('next');
const port = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
// Port
const server = express();
app.setAssetPrefix('test1');
// ======
// Routes
// ======
server.get('/test1/:id', (req, res) => {
const actualPage = `/${req.params.id}`;
const queryParams = { id: req.params.id };
app.render(req, res, actualPage, queryParams);
});
server.get('/test1', (req, res) => {
app.render(req, res, '/');
});
server.get('*', (req, res) => {
handle(req, res);
});
// =============
// End of Routes
// =============
server.listen(port, err => {
if (err) throw err;
console.log(`>Listening on PORT: ${port}`);
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
You need custom routing. Parse the incoming url and replace it with what you want.
Here is is an example to make /a resolve to /b, and /b to /a
https://github.com/zeit/next.js#custom-server-and-routing

Resources