Im making a simple app with react and node. On the react side I create a note with a unique-id and then the note can be found at mypage.com/unique-id using react-router-dom and useEffect in the loaded component to get the data from the database. This works perfect as long as my frontend and backend are being served from different ports. When I build the react app and place it in my nodejs app the app will work fine, until I reload mypage.com/unique-id and then im hit with a 404 on my server side. I have a bit of a grasp of what is going on - everything is being served from localhost:3001/ so when i reload localhost:3001/unique-id my server is looking for a route for that, which doesnt exist on my server side. I'm not sure how to connect the dots to serve my front end page at localhost:3001/unique-id with data from the server for that unique id. If i makea route on my server side it would just send back the raw data without serving the page that is suppose ot be at localhost:3001/unique-id
I had faced the same issue and it got resolved by adding * into the route
before route
app.get("/", (req, res) => {
res.header("Cache-Control", "max-age=-1");
res.header("Expires", "-1");
res.header("Pragma", "no-cache");
res.sendFile(path.join(__dirname, "build/index.html"));
});
after
app.get("/*", (req, res) => {
res.header("Cache-Control", "max-age=-1");
res.header("Expires", "-1");
res.header("Pragma", "no-cache");
res.sendFile(path.join(__dirname, "build/index.html"));
});
Related
I have not done this before I tried to see how it is done online but didn't see any reliable method. I keep seeing only the react.js part. I have a Middleware in node.js that returns route does not exist
const notFound = (req, res) => res.status(404).send('Route does not exist')
And I serve it this way in the app.js
app.use(notFoundMiddleware);
app.get('*', (req, res)=>{
res.sendFile(path.join(__dirname, 'build', 'index.html'));
})
This works in postman when I tested an invalid route. However, since I am serving my frontend below it, the code below it doesn't work. If I place the not found middleware below the frontend files, the frontend files would be served but the not found middleware won't work anymore.
How Am I supposed to serve not found middleware and serve it in frontend using react.js?
The problem appears when after reloading a page, server return only json instead that page
I'm using React and return static files from build folder, there is also express handles routing, it is reproduced only in production mode when running localhost everything ok
app.use('/auth', authRoutes);
app.use('/user', userRoutes);
app.use(['/dota2', '/csgo', '/lol'], generalRoutes);
if (process.env.REACT_APP_ENV === 'production') {
console.log('Production is running');
app.use('/', express.static(path.join(__dirname, '../build')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../build', 'index.html'));
});
}
There are routes
const router = Router();
router.get('/live', liveMatches);
router.get('/upcoming', upcomingMatches);
router.get('/past', pastMatches);
router.get('/:matchId', getMatchById);
router.get('/opponents/:tournamentId', opponents);
router.post('/past-team-matches', pastTeamMatches);
You can visit mySite and you will see json as result but if you clear matchId in URL and click on any match the page will load as normal
There is also react-router
<ServiceRoute
key={key}
path={['/dota2', '/csgo', '/lol']}
exact
access
component={Matches}
/>
<ServiceRoute
key={key}
path={['/dota2/:matchId', '/csgo/:matchId', '/lol/:matchId']}
exact
access
component={MatchInfo}
/>
Let's follow the route matching that express does in this case:
When looking for /dota2/566624, it will match here: app.use(['/dota2', '/csgo', '/lol'], generalRoutes); and return the JSON.
When looking for /dota2, it won't match app.use(['/dota2', '/csgo', '/lol'], generalRoutes); so it will continue down until it matches app.get('*', (req, res) => {, serving the React page.
The problem I see here, is that you're using the very same routes for the API and the front-end routing on React. Ideally, when serving the API and the front-end application from the same server you should prefix the API routes, that way they won't clash with the front-end routes. Let's say that you prefix the API routes with: /api. Now you we have:
app.use('/api/auth', authRoutes);
app.use('/api/user', userRoutes);
app.use(['/api/dota2', '/api/csgo', '/api/lol'], generalRoutes);
// ... everything is the same down here
/api/dota2/566624. Will match against the endpoint that returns the JSON on the first load.
/dota2/566624. Will not match the JSON endpoint and will follow down to the '*' route that loads the React app, later, once the app is loaded that route will be handled by the router you're using on the react application.
Don't add the prefix as I did in the example above, use the const router = Router(); you've been using for this purpose as well. I hard-coded the prefix so that I can keep the example short.
One last question is: Why is this not happening on development?
I don't have all the information but for what I can see you're serving the front-end application from a different server than the one running the API; in that case you won't have the route clashing, since they are server from different ports, e.g front-end served on localhost:8080 and API served on localhost:5000.
I hope this helps! please comment if you need info!
We made a late decision to implement social media sharing for Angular 7 project. As a first step of the re-write I wish to dynamically update social media tags for a particular route only ('/post/').
I am able to apply SSR on '/post/' using app.use in the server.ts file:
app.get('/api/**', (req, res) => { }); // ignore api requests
app.use('/post/', (req, res) => {
res.render('index', { req });
}); // successfully serves SSR content on '/post/' but client side rendering fails to take over.
app.get('*', (req, res) => console.log('Other routes')) // 'ERR_EMPTY_RESPONSE' error
I am running off localhost:4200 for both server and client - spinning up the SSR node server with npm run serve:ssr, and spin up the client side with ng serve.
I am unsure the best way to handle requests for different routes. How can I tell Node to skip other routes and to spin up Angular on the client side? Currently it returns 'ERR_EMPTY_RESPONSE' error on other routes and only provides SSR content for '/posts/' (no client side rendering).
I am writing a web application using Node/Express for backend and React for frontend. They are sitting on the same server and I use /api to differentiate the web pages vs api services. However, I am having trouble redirecting all my traffic to https from http. I've narrowed it down to a problem that my code is rendering its frontend calls to static pages:
app.use(express.static(__dirname+'/public'));
// Redirect all traffic to https
app.all('*', function(req, res, next){
console.log('req start: ',req.secure, req.hostname, req.url,
app.get('port'));
if (req.secure) {
return next();
}
res.redirect('https://'+req.hostname + ':' + app.get('secPort') + req.url);
});
// Allow browserHistory
app.get('*', (req, res) => {
res.sendFile(__dirname+'/public/index.html');
})
So I am assuming that the reason why it's not redirecting to https is that it is sending a html file on the server instead of serving the actual webapp. I was wondering if any of you have any insights on how to go about this, whether I need to separate the webapp from my api services, or is it something I can change within React?
I'm using Express, which loads AngularJS from a static directory. Normally, I will request http://localhost/, in which Express serves me my index.html and all of the correct Angular files, etc. In my Angular app, I have these routes setup, which replace the content in an ng-view:
$routeProvider.when('/', {
templateUrl: '/partials/main.html',
controller: MainCtrl,
});
$routeProvider.when('/project/:projectId', {
templateUrl: '/partials/project.html',
controller: ProjectCtrl,
});
$locationProvider.html5Mode(true);
On my main page, I have a link to <a href="/project/{{project.id}}">, which will successfully load the template and direct me to http://localhost/project/3 or whatever ID I have specified. The problem is when I try to direct my browser to http://localhost/project/3 or refresh the page, the request is going to the Express/Node server, which returns Cannot GET /project/3.
How do I setup my Express routes to accommodate for this? I'm guessing it will require the use of $location in Angular (although I'd prefer to avoid the ugly ?searches and #hashes they use), but I'm clueless about how to go about setting up the Express routes to handle this.
Thanks.
with express 4, you probably want to catch all requests and redirect to angularjs index.html page.
app.use(app.router); doesn't exist anymore and res.sendfile is deprecated, use res.sendFilewith an uppercase F.
app.post('/projects/', projectController.createProject);
app.get('/projects/:id', projectController.getProject);
app.get('*', function (req, res) {
res.sendFile('/public/index.html');
});
put all your API routes before the route for every path app.get('*', function (req, res){...})
I would create a catch-all handler that runs after your regular routes that sends the necessary data.
app = express();
// your normal configuration like `app.use(express.bodyParser());` here
// ...
app.use(app.router);
app.use(function(req, res) {
// Use res.sendfile, as it streams instead of reading the file into memory.
res.sendfile(__dirname + '/public/index.html');
});
app.router is the middleware that runs all of your Express routes (like app.get and app.post); normally, Express puts this at the very end of the middleware chain automatically, but you can also add it to the chain explicitly, like we did here.
Then, if the URL isn't handled by app.router, the last middleware will send the Angular HTML view down to the client. This will happen for any URL that isn't handled by the other middleware, so your Angular app will have to handle invalid routes correctly.
I guess I should have clarified that I wasn't interested in using a template engine, but having Angular pull all of the HTML partials on it's own, Node is functioning completely as a static server here (but it won't be for the JSON API. Brian Ford shows how to do it using Jade here: http://briantford.com/blog/angular-express.html
My app is a single-page app, so I created an Express route for each possible URL pattern, and each of them does the same thing.
fs.readFile(__dirname + '/public/index.html', 'utf8', function(err, content) {
res.send(content);
});
I was assuming I would have to pass some request variables to Angular, but it looks like Angular takes care of it automatically.