Why must I include the host with URLs with node web requests? - node.js

No matter which library I use for node, they all require absolute URLs.
This means I need to either build a fetch curry, then pass that fetch through function chains to be able to make a request, OR I need to make a constant that is defined after figuring out whether im in production or development, then update that URL whenever my environments change.
Regardless, why does node require the hostname for URL's?
Is there a more seamless way to do server side requests anywhere in my app (including deep in function chains)?
A code example:
node index.js
index.js
let app = Express();
app.use('ace', (req, res) => foo());
app.use('somedata.json', (req, res) => res.status(200).send('{"hello": "world"}'));
foo.js
() => bar();
bar.js
() => bat();
bat.js
() => fetch('/somedata.json').then(console.log);

There is no such thing as a relative HTTP request. Any actual HTTP request must be a fully qualified URL. That's the HTTP specification. Because HTTP is stateless, there is no "base path" state associated with a given host.
Relative requests exist in a browser-type environment, but that's only because the browser pre-processes the request and, if it's not absolute, the browser adds on a default base path to make it absolute. All requests coming from a browser to a server are actually absolute URLs.
You could write your own function that did the same thing the browser does. You set a base path on it and then you direct all your requests through this function that checks the URL sent for the request and if it's not a fully qualified path, then the base path is added to it.
We could help you more specifically if you showed a real code example of the problem you're trying to solve. If it's one of dev or production environment, then you would typically establish some variables at startup base don which type of environment you're running in and then just have your code use those variables whenever it forms a request.

Related

Https createServer, load cookie and load clients index.html

I am trying to setup a login system on a website.
In order to do that, I have to load http only cookies.
In order to load them, I have to send them back to the client via the response object in the createServer function when https starts up.
I have successfully done that via here:
setting up https cookie in nodejs
The problem is twofold.
The https server cookie only loads if I include the port number in the url.
How do I get it to load without including the port number?
When the server kicks in and loads the cookie, the static index.html that was always supposed to load on the client, doesn't load and instead all i get is what was written into the response object on the server. How do I get to load the cookie, and just load that static html file?
I have tried sending in the entire html file as a respnose from the server side. But I'm not sure about that, plus i get MIME type problems in the browser.
I am not sure for the first part but for 2nd one,
you have to properly mention about response data type in response header.
so your should be something like this one:
var app = express(); app.get('/test', function(req, res) { res.sendFile('views/test.html', {root:__dirname}) });
For your first part of the question "How do I get it to load without including the port number?" You can try creating virtual host e.g for localhost:3000 will be something.xyz.
And for your second part you need to serve index.html with render method as follow
server.get('/', function (req, res) {
res.render('index', { greeting: 'Welcome' });
});
Where index is you static file inside view directory.
I've created a small demo, that might get you on the right track:
https://github.com/bergur/simple-server-with-websocket
This example includes:
https web server
websocket server
logic to get the cookies
serving a temp.html file without express
example of javascript class
example of dependency injection in nodejs

What does localhost:1337 become in production?

I'm sure this question is very basic but it's confusing me.
Currently in development mode my backend runs in localhost:1337 (using Strapi cms to be precise).
But what will it turn into when the website is deployed to a web server?
Specifically, the website will reside in a sub-directory and not in the root, will it affect this?
Currently this is a url I'm using inside of my project as images src:
localhost:1337/uploads/image-example.jpg
I'm trying to understnad what will be the new url once the project has been deployed, and what's more it's deployed in a subdirectory and not in the root
Thanks in advance
You shouldn't have to do anything.
Most, if not all, web hosts use the PORT environment variable to configure the application server. I just did a quick code search through Strapi and found this:
"port": "${process.env.PORT || 1337}",
to read the environment variable or use a default value (instead of asking for a random port with 0, for predictability while developing). If you used their starter script, I would assume your application has the same.
In many cases, this is sufficient, with two exceptions.
If your application server doesn't know its URL, it can only generate relative URLs. For example, it won't be able to compose an email containing a link to itself.
HTTP redirects required an absolute URL once upon a time, but that has since been amended.
Setting just the port assumes that the application will be mounted on /. If, for example, you were configuring your own web server (instead of Heroku), and you wished to mount your application on /blog, you would need some way to tell your application so that it can put the right prefix on paths.
It might be possible to get around this by restricting the URLs to relative paths only, but that sounds tedious and I don't think it's usually done. And an incoming request doesn't actually have enough information to discern the URL that the user is looking at. Instead, you show the URL to your app out of band.
For example, Grafana has a root_url variable in its config file where you put the full URL prefix, Prometheus takes a -web.external-url argument, etc.
However, I don't think Heroku can mount your application anywhere other than /, so the port should be sufficient.
Here's a complete server that runs on Heroku and shows its environment to you:
const app = require("express")();
app.set("json spaces", 2);
app.get("/", (req, res) => {
res.send(process.env);
});
const server = app.listen(process.env.PORT, () => {
console.log('server is up on', server.address());
});
The PORT variable is all the configuration it needs; the environment does not include the app name.
Hardcoding the production URL of your app can become a maintenance burden, so make sure it remains configurable with a command line argument or environment variable if you do end up teaching your app what its URL is.
So to answer your question specifically, your image src should begin with /uploads.

What does http and https module do in Node?

Can someone help me in understanding what does http and https module do in Express?
I was going through the following docs on w3schools
From definition it says
Node.js has a built-in module called HTTP, which allows Node.js to
transfer data over the Hyper Text Transfer Protocol (HTTP).
With following example
var http = require('http');
//create a server object:
http.createServer(function (req, res) {
res.write('Hello World!'); //write a response to the client
res.end(); //end the response
}).listen(8080); //the server object listens on port 8080
This is the example to live demo
First, I am unable to comprehend their example like Where are they making (route) request so that they are receiving response?
Second by the definition, to make a request, using libraries like axios can be alternative?
third, when we make an api request, isn't the data transferred over http/https?
app.post("/", (req, res) => {
In short, Can someone please explain me in more human words the use of http package in express?
Update: I might be confusing this with express, I am used to using express and here we aren't using express
1- They aren't defining any route. That piece of code only creates a server running on port 8080 that when it's created or accessed on the home route (/) returns "Hello World". If you want to define routes you should take a closer look to a module called express that it's used by most of node users due to its simplicity and documentation (https://expressjs.com/en/starter/hello-world.html) In that link you have an example for creating the server and a basic route
2- Yes it can and should be because they are way better than the default from nodeJs. Take a look at axios or superagent, superagent it's better if you want to use formdata to send images or attachments.
3- By default, all servers created using http or express are http servers (don't have a certificate to encrypt the data so they aren't secure). If you want a https server, you can buy certificates or use https://letsencrypt.org/ this module that generates free SSL certificates with 1 month validation.
http module has multiple functions, it can be used to create a server, to make http requests and so on. It's up to you to decide which submodule from the package you want to use. Express is built over the http module making everything easier.
If you need more explanation, tell me and I will try to explain a little better.

Redirect with express in serverless/lambda container not working

I have setup an express application with various routes like:
/api/route1
/api/route2
/api/newroute
…
I need to redirect a request for route /api/route2 to /api/newroute. Thus I use res.redirect(); to achieve this. It works fine on my local development environment, where the application is hosted on http://localhost/api. A request for http://localhost/api/route2 gets successfully redirected to http://localhost/api/newroute.
We have now deployed the express application in a serverless/lambda container using aws-serverless-express. The application is hosted by AWS on https://xxx.execute-api.us-east-1.amazonaws.com/production/api.
In case of a request for:
https://xxx.execute-api.us-east-1.amazonaws.com/production/api/route2
it gets redirected to:
https://xxx.execute-api.us-east-1.amazonaws.com/api/newroute.
The redirect fails as the correct endpoint should be now /production/api/newroute.
I would like to avoid to hardcode the infix “/production” in res.redirect(); as the it will vary due to environment.
Thus I have checked whether
req.originalUrl
req.baseUrl
req.path
will provide the infix “/production”, however this is not the case.
Also req.get('Host') does not provide “/production” as it returns https://xxx.execute-api.us-east-1.amazonaws.com.
Are there any other options how I could get the full URL where the application is hosted? Or are there any better ideas?
I ran into this same issue. Here's my solution:
const baseUrl = req.url
.replace(
event.pathParameters.proxy, // => returns api/your/path
event.requestContext.path // => returns /production//api/your/path
)
.split('//') // fix the double-slashes (//)
.join('/');

Is directory traversal via request.url possible?

I'm coming from PHP, where you can inject double dots into a URL to try directory traversal. In NodeJS, it seems that you get the Http webserver automatically removes the double dots from the URL.
For example, if you go to http://example.com/static/../app.js, it seems like Node redirects to http://example.com/app.js, which then throws a 404 in my case, because there is no callback for URLs not starting with /static/.
Is it safe to assume that directory traversal via request.url is not possible in a NodeJS HTTP webserver created using the http package?
I was gonna say that you can be sure that it's not possible, then I tried and I have to say that no, it doesn't seem like the http module removes '/../'. The redirection you saw is done in the browser. So whether it's a security risk or not depends on how your static handler is implemented.
Proof of concept:
// Server
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(req.url);
}).listen(1337);
Curl it:
curl --path-as-is "http://localhost:1337/static/../app.js"
# /static/../app.js
So if you use a homebuilt static handler that just uses path.resolve() you're screwed. Hopefully popular ones like express.static have thought about this, but i haven't tried it.
Update
Express indeed responds with a 404 "Error: Forbidden".

Resources