How to communicate between locally running web services - node.js

I have some back-end services which can be called only through an API Gateway server. the back-end services are in Spring rest service and API GateWay is a Node Server .these two servers are running locally on different ports(backend:8080 , node :3000).
How can i make a request to back-end service from my node Server ?

If they both expose rest API you can make use of the inbuilt- http module for communication
require('http');
var options = {
host: 'www.google.com',
port: 80,
path: '/index.html'
};
http.get(options, function(res) {
console.log("Got response: " + res.statusCode);
res.on("data", function(chunk) {
console.log("BODY: " + chunk);
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
But i would recommend using libraries like superagent or axios

Related

how can a path and a host be completely different in nodejs

I'm doing research in proxies in nodejs. I came across something that blew my mind. In one of the options for a http.request connection, the source code showed this as the options object
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
This was a part of a far bigger code which was the whole tunneling system. But can someone just explain how the options above work? The whole code is below
const http = require('http');
const net = require('net');
const { URL } = require('url');
// Create an HTTP tunneling proxy
const proxy = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {
// Make a request to a tunneling proxy
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
const req = http.request(options);
req.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});
Source: https://nodejs.org/api/http.html#http_event_connect
You probably have never used a network that requires you to configure a HTTP proxy. Most networks these days configure their firewall to allow HTTP traffic. This means most people these days have never needed to use a HTTP proxy to access the web.
A long-long time ago when I first started using the internet (around 1994) a lot of networks don't allow transparent internet access. Your PC does not have any connection to the outside world. But sysadmins would install a HTTP proxy that you can connect to. Your PC would only have access to the LAN (which the proxy is a part of) and only the HTTP proxy would have access to the internet.
Here's an example of how you'd configure Windows to use a HTTP proxy:
If you configure your PC as above, then when you connect to www.google.com your browser would connect to the host proxy.example.com on port 8080 and then request it to fetch data from www.google.com.
As for why it calls the requested resource path it's because it is sent in the "path" part of the packet.
For example, a normal GET request for getting this page looks something like this:
GET /questions/60498963 HTTP/1.1
Host: stackoverflow.com
And the string after GET and before protocol version is normally called the path:
.---------- this is normally called
| the "path"
v
GET /questions/60498963 HTTP/1.1
Host: stackoverflow.com
When making a proxy request the HTTP header looks like this:
CONNECT stackoverflow.com/questions/60498963 HTTP/1.1
So the url including the domain name is sent to the proxy in the part of the packet usually used to send file path.
Note that all this has nothing to do with Node.js. This is just basic networking (no programming languages involved).

How to skip specifying port in Node.js http.request

I am using node.js to connect to NetSuite's REST api. Issue is, I dont know what is port number in NetSuite.. so I want to skip specifying port number. When I dont provide a port number, it takes 80 (default) which is not correct. I have tried port 443 as its https but its not correct port for NetSuite.
I am getting error "getaddrinfo ENOTFOUND". Here is my code.
exports.helloGET = function helloGET (req, res) {
//remove extra node
var json_build = '{"__type" : "salesorder", "status":"Approved"}';
console.log(json_build);
//call NS rest api
var options = {
host: 'rest.na2.netsuite.com',
path: '/app/site/hosting/restlet.nl?script=55&deploy=1',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Keep-alive': 'timeout=30',
'Authorization' : 'NLAuth nlauth_account="4678710", nlauth_email="someemail#domain.com", nlauth_signature="password", nlauth_role="3"'
}
};
var http = require('http');
var post_req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end',function(){
console.log('response ended');
});
});
post_req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
//post data
post_req.write(json_build);
post_req.end();
};
It goes inside "post_req.on error".
The error ENOTFOUND typically means that the host you are specifying cannot be found in DNS so that may actually be where your error is. Several possible reasons for this here: What ENOTFOUND error in an http request, happening time to time, means?.
You have to know the port in order to connect. You cannot skip it. A TCP connection requires a destination IP address AND a port number. You can't make a TCP connection (which is what's under an HTTP connection) without the port number.
As you appear to know, the default port for HTTP is port 80 and the default port for HTTPS is 443. With http.request(), it will be port 80 unless you specify the port. With https.request() (note different https module), then it will be 443 if you don't specify the port.
So, the only answer here is for you to find out what port the service is running on that you want to connect to. If it isn't a well-known port known in advance, then there needs to be a way to query what port it's running on from some other known service or configuration data.
Also, if you're trying to connection to an HTTPS service, you need to use the https module, not the http module.
You’re actually not connecting to the correct host.
Use the getdatacenters API to look up the RESTlet host for your account.

How can I make a successful http POST using node.js to an aws instance?

I am working on setting up an aws instance to listen for http POST's. When running the server and client both as local host, everything seems to work fine. However, when running trying to make a post with the client to an aws instance with the server running, I am getting a connect ECONNREFUSED error.
The aws instance (ubuntu server) that I am using has both ports 80 and 8080 open to all ip addresses. I am using the pm2 module to keep the server running. Although using pm2 is giving the same error.
Server Setup: (aws instance terminal)
$ sudo apt-get install git
$ curl -sL https://deb.nodesource.com/setup | sudo bash -
$ sudo apt-get install -y nodejs
$ sudo npm install pm2 -g --unsafe-perm
Using node to start server:
$ node nodeServerTest.js
Using pm2 to start server:
$ pm2 start nodeServerTest.js --name "nodeServerTest" -i max
Server Code:
// nodeServerTest.js
var http = require("http");
function startServer(port, ip) {
// requestListener handles incoming requests
function requestListener(request, response) {
if (request.method == 'POST') {
var body = '';
request.on('data', function (data) {
body += data;
// destroys connection if too long
if (body.length > 1e6) {
request.connection.destroy();
}
});
request.on('end', function() {
// checks for json, otherwise destroys connection
try {
var POST = JSON.parse(body);
console.log('valid post:')
console.log(POST)
response.end('post accepted');
}
catch(err) {
console.log('bad post, ending connection')
response.connection.destroy();
}
});
}
else {
response.end();
}
};
// creates the eventEmitter
var server = http.createServer(requestListener);
// beigns listening on specified port
server.listen(port, ip);
// logs when someone attempts to connect
server.on('connection', function (stream) {
console.log('someone connected!');
});
// notifies when server has started
console.log('Server running at http://'+ip+':'+port);
}
startServer(8080, '127.0.0.1');
Client Code: (I change the host field to the ip address when attempting to post to the aws instance)
// nodeClientTest.js
function httpPost() {
var http = require("http");
var postData = JSON.stringify({
'msg': 'Hello World!'
});
var options = {
host: "localhost", // using correct public ip
port: 8080,
method: 'POST',
path: '/',
headers: {
'Content-Type': 'application/json',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postData);
req.end();
}
httpPost();
Thank you for any help, if more information is needed please leave a comment
You are binding your server to the loopback interface here:
startServer(8080, '127.0.0.1');
..which makes is available only locally. To allow access via your eth0 interface, so from other network hosts replace this line with:
startServer(8080);
..to listen on port 8080 TCP on all interfaces, according to Node.js manual.
PS Please remember that your private IP on AWS EC2 != public IP address. You can check both by running ec2metadata command on your EC2 host.
An explanation, as OP requested:
each TCP server socket has to be bound to a specific network interface. This is because you make you connect your client TCP socket to a combination of IP:port and the IP is bound to the interface.
loopback interface with a 127.0.0.1 IP address is as special virtual interface available only from the localhost, targeting ifself (hence the name),
So when you run your server binding it to loopback the only way you could have only made the request to it would be initiating the connection from that host itself, for example with telnet like this: telnet 127.0.0.1 8080.
You could have bind the server to the actual IP of eth0 interface but this is inpractical, especially on EC2 servers where private IPs change.
That's why I proposed the simpler, universal syntax. A side effect is that this way your server listens on both loopback and eth0 but it only helps, for example when you want to separate your own, local traffic from the rest of the traffic by based on the interface used.
It seems like your server is only binding to the local address of the server (127.0.0.1) and not listening to connections outside of the server.
Please try to change the listening address of the server to 0.0.0.0
startServer(8080, '0.0.0.0');
I would also advise you to check the express web framework for your server.

nodejs make a GET call to an https site

i am using nodejs v0.10.28 on ubuntu 12LTS,
am trying to make a request to https enable site behind a web proxy using this test code:
var http = require("http");
var options = {
host: "mycompany.proxy.host",
port: 8088,
//host: "https://login.launchpad.net",
//port: 443,
//path: "/",
headers: {
Host: "login.launchpad.net"
}
};
http.get(options, function(res) {
console.log(res);
res.pipe(process.stdout);
}).on('error', function(e) {
console.log(e);
});
but am not sure what are the correct option params to use to make a successful HTTP GET
You should be using node https instead of http module for making https requests. Otherwise the server will most likely reset your connection, and an ECONNRESET error will be caught by the error handler.

Simple example for nodejs behind a proxy

Here is a simple nodejs script for using node as an https client to interact with the outside world. How do you modify it so you don't get "ECONNREFUSED" errors when you run it behind a corporate proxy like http://10.10.10.10:8080 ?
var https = require('https');
var options = {
hostname: 'encrypted.google.com',
port: 443,
path: '/',
method: 'GET'
};
var req = https.request(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
});
req.end();
req.on('error', function(e) {
console.error(e);
});
----Update---
I figured out how to with the npm 'request' package (https://github.com/mikeal/request). Still wondering how to do this with vanilla node libraries.
var request = require('request').defaults({proxy:'http://my.proxy.server:8080', agent:false});
request('https://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the google web page.
}
})
Normally its best to handle proxying at the system level - configure your operating system to use the proxy not the script. However this may also fail, as most corporate proxies don't have all the ports open.
A universal solution would be to have a server (EC2 or Rackspace instance) to act as your own proxy and have it listen for ssh on port 443.Port 443 is open in corporate firewalls for https.
At which point you can either tunnel all you local network traffic to the server, or ssh to the server and run the script there.
If you were to make scripts proxy specific, they wouldn't be very portable, and not production hardened as they'd break when the proxy configuration changed.

Resources