Node URL gets "undefined" added to URL path - javascript

I have a site that exists on a dev, staging and production server. On the dev and staging server the functionality is 100% fine, however on the production server the strangest thing happens - "undefined" gets added to the URL path.
Here is the short example of what is happening:
In the index.html I have an anchor tag to logout of a session with passport: Logout.
It goes to this route on my node server:
// passport oauth logout
routes.get('/auth/logout', (req, res) => {
req.session.destroy((e) => {
req.logout();
res.redirect(config.redirects.env.prod);
});
});
On dev and staging this destroys the session and redirects you to /. On production, when you click the button it takes you to this URL randomly https://somesite.com/auth/undefined.
Any ideas on how to debug this? It is making no sense to me and there's nothing I'm finding serverside or in the markup that would cause this, especially since it is functional on dev and staging. All servers are Ubuntu servers set up exactly the same way.

I was able to resolve this. Oddly enough, 400 lines down in a completely unrelated route used for file uploads, I had a line of code that referenced config.redirects.env.production instead of config.redirects.env.prod. I wasn't even looking at that route because it wasn't even part of functionality i was testing at the moment and I saw no errors spit out (again, since the route wasnt being referenced/used yet).
Fixing that typo resolved this bizarre issue of "undefined" being inserted into the URL. Still not sure how it managed to bubble up like that.

Related

Internal server error 403 on deploying react app served via expressjs

I am trying to serve a build react application using expressjs. the react application is built and the index.html is served from my expressjs using:
app.use('/', express.static('reactapp/build'))
The application is simple. it contains a number of cards which when pressing navigates to another page changing the route. Before clicking, it is suppose localhost:3000/lists and after clicking any cards, it routes to localhosts/lists/1, 1 being an id. Now, when i try to refresh the page after pressing the any one of the cards, i get "no handler found for the path"(because it is client side url i suppose and isnot handled by express). the last app.use gets triggered.
app.use((req, res) => {
res.status(404).json({message: `No handler for ${req.url}`, requestHost: req.baseUrl})
})
therefore, what i did was, i sent the index.html inside this middleware part to fix my issue.
app.use((req, res) => {
res.sendFile(path.join(__dirname,"..\\reactapp\\build","index.html"));
})
it solved the problem locally but after deploying i get the "internal server error of status code 403". i am not knowing what the problem is. according to a site: The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it...If authentication credentials were provided in the request, the server considers them insufficient to grant access.
Could someone help me out? i am not much familiar with expressjs so i wanted some help on what might be the reason.
res.sendFile(path.join(__dirname,"..\reactapp\build","index.html"));
the way path is setup, doesnot work for linux machines. that might be the reason.

How to set Heroku Port for NodeJS Express App?

so I'm trying to host my website on Heroku and set up everything to get my app up and running.
Whenever I try to submit the form I get undefined errors.
Undefined Errors Console Errors
I've set it up to use the port like shown in the documenation:
app.listen(process.env.PORT || 8081, function () {
console.log('Example app listening on port 8081!');
});
When starting the app locally with heroku local web I get Typerror: Failed to Fetch and the undefined results but when I go into my .env file and add a port=8081 it works perfectly fine.
Good result
When I open it with heroku open I still have that undefined problem.
I don't really have to set a PORT in .env right? Or do I?
I read that that standard port is 80 but that didn't work either.
Can someone please help me?
Thank you!
Heres the link to the public site: https://shrouded-everglades-61993.herokuapp.com/
Here the link to my Github rep: https://github.com/stefanfeldner/capstone-travel-app
So the reason that they're undefined is that they are being set by these lines in main.js:
uiData.imageURL = data[1].imageUrl;
...
uiData.iconCode = data[0].iconCode;
Where data is the object you're retrieving from your /getData endpoint. The problem is that what /getData actually returns is [{}, {}] so of course these values are both undefined, leading to that visual broken-ness.
Now, why does /getData return these empty objects? I can't check your server logs, but there are two obvious possibilities based on the way server.js is written.
The first is that there's an error somewhere and you're simply not making it all the way to the end of your try-catch in callApi, so neither weatherData nor pixabayData are being updated.
Second, it's also possible that these calls are successful but that the desired data is not in the results, i.e. that neither of these if statements are true:
if('city_name' in data) {`
...
if('hits' in data) {
Again, in this case, neither weatherData nor pixabayData are being updated.
The way that your handler for /sendFormData is written, it doesn't check that callApi actually got any useful data, just that it has finished execution. So your code flow continues on its merry way despite the data objects still being empty.
However, there's a bigger, unrelated design flaw here: What happens if more than one person uses your website? Your client-side code calls /sendFormData, which hopefully correctly populates the global variables weatherData and pixabayData, and then separately calls /getData to try and retrieve this data.
The thing is, though, between the time your client-side calls /sendFormData and /getData, anyone else using your website could separately call /sendFormData and change the data contained in the global variables from the result of your search to the result of their search. So you'd get their search results back instead of yours, since their results overwrote your results on the server. You need to handle getting the API results and sending them back to the requester in a single transaction.
(Re: all the local Heroku Config, that's hard to answer without messing around with your local computer, sorry.)

SailsJS Custom API Hook - Subdomain

I recently tried to deploy a SailsJS app to an AWS environment, and thus I set up the relevant staging and production env files.
One persistent issue I had however was when I ran the app with:
sails lift --staging
I noticed I either got recurring redirects or it was not reachable at all.
After some further digging, I happened to come across this code located in the api/hooks/custom/index.js file:
// Next, if we're running in our actual "production" or "staging" Sails
// environment, check if this is a GET request via some other subdomain,
// for example something like `webhooks.` or `click.`. If so, we'll
// automatically go ahead and redirect to the corresponding path under
// our base URL, which is environment-specific.
// > Note that we DO NOT redirect virtual socket requests and we DO NOT
// > redirect non-GET requests (because it can confuse some 3rd party
// > platforms that send webhook requests.)
var configuredBaseSubdomain;
try {
configuredBaseSubdomain = url.parse(sails.config.custom.baseUrl).host.match(/^([^\.]+)\./)[1];
} catch (unusedErr) { /*…*/}
if ((sails.config.environment === 'staging' || sails.config.environment === 'production') && !req.isSocket && req.method === 'GET' && req.subdomains[0] !== configuredBaseSubdomain) {
sails.log.info('Redirecting GET request from `'+req.subdomains[0]+'.` subdomain...');
return res.redirect(sails.config.custom.baseUrl+req.url);
}//•
I tried to ask around on the IRC channels and Gitter.im links, but my queries 'got lost in the noise' per-say, so thought I'd just ask here and leave it up for discussion. Is there not a better way to handle this?
Deploying on an AWS environment with a URL http://ec2-xxx-xxx-xxx-xxx.locale-x.compute.amazonaws.com or just accessing via an IP address are both caught by the regex used:
/^([^\.]+)\./
Which makes deploying quite hard unless the app is in the root route (haha) of a site. Is there not another way to handle this?
For now, I've had to comment it out just so my staged app is usable/testable. I also realise that this might have been rendered via a parameter passed when initially creating my project via the sails-generate project, but I haven't tracked it down yet
i was running into the same issue. Seems we both used the generator at a time that resulted in the code including the regex above. It is now changed with this commit and as soon as you change the code in your repo to the below it actually works again!
https://github.com/balderdashy/sails-generate/commit/76e2096d8173d474b6152a67ff4cfa08c38e6460

Django/React app API in production vs development?

So I have made a React app that uses Axios to fetch api's. During development, I would have an api call to 127.0.0.1. However, my ReactApp resided on localhost:3000. Therefore, it development, I can't just use:
axios.get('/api/'),
In dev I would need to use:
axios.get('127.0.0.1/api/'),
Anybody have any good ideas on how to resolve this conflict so I can see some data in dev? Kinda tough to design an UI without any data to populate it. Kinda like buying a shirt without trying it on first (which, I never try anything on, so this is a horrible analogy.)
Use it as in the first example. Because it is relative, it will resolve fine for different hosts:
axios.get('/api')
Will automatically resolve to:
// if called by https://example.com/index.js for example
"https://example.com/api"
// if called by localhost/index.js
"https(s)://localhost/api"
In your second example, if you prepend the host and port, you will get duplication!
For example, I just tried your first example on my localhost:3000 and the result is
GET http://localhost:3000/api 404 (Not Found)
Which makes sense because I don't have a /api. But did you notice it appended /api correctly after my host and port?
Now your second example:
GET http://localhost:3000/127.0.0.1/api 404 (Not Found)
It duplicates the host and port. In your case it would be 127.0.0.1:3000/127.0.0.1/api
Just use the first example and it will resolve fine for different hosts (and ports) because it's relative! Did you try it out?

AngularJS - Best Way to Handle State on Manually Entered URLs

I currently have a set-up based on the meanjs stack boilerplate where I can have users logged in this state of being 'logged-in' stays as I navigate the URLs of the site. This is due to holding the user object in a Service which becomes globally available.
However this only works if I navigate from my base root, i.e. from '/' and by navigation only within my app.
If I manually enter a URL such as '/page1' it loses the global user object, however if I go to my root homepage and navigate to '/page1' via the site. Then it's fine, it sees the global user object in the Service object.
So I guess this happens due to the full page refresh which loses the global value where is navigating via the site does not do a refresh so you keep all your variables.
Some things to note:
I have enabled HTML5Mode, using prefix of '!'.
I use UI-Router
I use a tag with '/'
I have a re-write rule on express that after loading all my routes, I have one last route that takes all '/*' to and sends back the root index.html file, as that is where the angularjs stuff is.
I'm just wondering what people generally do here? Do they revert the standard cookies and local storage solutions? I'm fairly new to angular so I am guessing there are libraries out there for this.
I just would like to know what the recommended way to deal with this or what the majority do, just so I am aligned in the right way and angular way I suppose.
Update:
If I manually navigate to another URL on my site via the address bar, I lose my user state, however if I manually go back to my root via the address bar, my user state is seen again, so it is not simply about loosing state on window refresh. So it seems it is related to code running on root URL.
I have an express re-write that manually entered URLs (due to HTML5 Location Mode) should return the index.html first as it contains the AngularJs files and then the UI-Route takes over and routes it properly.
So I would have expected that any code on the root would have executed anyway, so it should be similar to navigating via the site or typing in the address bar. I must be missing something about Angular that has this effect.
Update 2
Right so more investigation lead me to this:
<script type="text/javascript">
var user = {{ user | json | safe }};
</script>
Which is a server side code for index.html, I guess this is not run when refreshing the page to a new page via a manual URL.
Using the hash bang mode, it works, which is because with hash bang mode, even I type a URL in the browser, it does not cause a refresh, where as using HTML5 Mode, it does refresh. So right now the solution I can think of is using sessionStorage.
Unless there better alternatives?
Update 3:
It seems the best way to handle this when using HTML5Mode is that you just have to have a re-write on the express server and few other things.
I think you have it right, but you may want to look at all the routes that your app may need and just consider some basic structure (api, user, session, partials etc). It just seems like one of those issues where it's as complicated as you want to let it become.
As far as the best practice you can follow the angular-fullstack-generator or the meanio project.
What you are doing looks closest to the mean.io mostly because they also use the ui-router, although they seem to have kept the hashbang and it looks like of more of an SEO friendly with some independant SPA page(s) capability.
You can probably install it and find the code before I explained it here so -
npm install -g meanio
mean init name
cd [name] && npm install
The angular-fullstack looks like this which is a good example of a more typical routing:
// Server API Routes
app.route('/api/awesomeThings')
.get(api.awesomeThings);
app.route('/api/users')
.post(users.create)
.put(users.changePassword);
app.route('/api/users/me')
.get(users.me);
app.route('/api/users/:id')
.get(users.show);
app.route('/api/session')
.post(session.login)
.delete(session.logout);
// All undefined api routes should return a 404
app.route('/api/*')
.get(function(req, res) {
res.send(404);
});
// All other routes to use Angular routing in app/scripts/app.js
app.route('/partials/*')
.get(index.partials);
app.route('/*')
.get( middleware.setUserCookie, index.index);
The partials are then found with some regex for simplicity and delivered without rendering like:
var path = require('path');
exports.partials = function(req, res) {
var stripped = req.url.split('.')[0];
var requestedView = path.join('./', stripped);
res.render(requestedView, function(err, html) {
if(err) {
console.log("Error rendering partial '" + requestedView + "'\n", err);
res.status(404);
res.send(404);
} else {
res.send(html);
}
});
};
And the index is rendered:
exports.index = function(req, res) {
res.render('index');
};
In the end I did have quite a bit of trouble but managed to get it to work by doing few things that can be broken down in to steps, which apply to those who are using HTML5Mode.
1) After enabling HTML5Mode in Angular, set a re-write on your server so that it sends back your index.html that contains the Angular src js files. Note, this re-write should be at the end after your static files and normal server routes (e.g. after your REST API routes).
2) Make sure that angular routes are not the same as your server routes. So if you have a front-end state /user/account, then do not have a server route /user/account otherwise it will not get called, change your server-side route to something like /api/v1/server/route.
3) For all anchor tags in your front-end that are meant to trigger a direct call to the server without having to go through Angular state/route, make sure you add a 'target=_self'.

Categories