I need to create forwarding proxy (not reverse proxy), there are two packages for Node.js http-proxy and request
I don't understand what's the difference between those in case of creating proxy? Are they doing exactly the same, or there are some tricky corner cases?
http-proxy
var http = require('http');
var proxy = require('http-proxy').createProxyServer();
http.createServer(function(req, res) {
proxy.web(req, res, {
target: "http://" + req.headers.host
});
}).listen(3000, 'localhost');
request
var http = require('http');
var request = require('request');
http.createServer(function(req, res) {
req.pipe(request(req.url)).pipe(res);
}).listen(3000, 'localhost');
The two examples you've given are functionally the same, though I would still prefer http-proxy, as it already comes with some assumptions that you are specifically creating reverse/forward proxy requests.
Related
I recently decided to learn socket.io, to make something real-time. I wrote something up, following the Get Started page on the site, and tested it locally until I got it working properly.
I uploaded it to my server using the same process as anything else. I ran it on port 8002, and added it to my reverse proxy (using http-proxy-middleware) under /pong/*. I then proxied /socket.io/* to port 8002 before it worked. However after inspection with Firefox I noticed that socket.io was only using polling as a transport method and not websockets, and after some further thought I decided that sending /socket.io/* to 8002 is not going to be good when using socket.io on other projects in the future.
So I ask, how do I get multiple socket.io programs running behind a reverse proxy, using websockets as a for transport?
proxy.js
const express = require("express")
const fs = require('fs');
const http = require('http');
const https = require('https');
const proxy = require('http-proxy-middleware');
const privateKey = fs.readFileSync('/etc/[path-to- letsencrypt]/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/[path-to-letsencrypt]/cert.pem', 'utf8');
const ca = fs.readFileSync('/[path-to-letsencrypt]/chain.pem', 'utf8');
var credentials = {key: privateKey, cert: certificate, ca: ca};
var app = express();
app.use(function (req, res, next) {
console.log(req.url)
next()
})
app.use("/pong/*", proxy({ target: "http://localhost:8002", pathRewrite: {"^/pong": ""}, ws:true, changeOrigin: true }))
app.use("/pnw/war/*", proxy({ target: "http://localhost:8000" }))
app.use("/pnw/nation/*", proxy({ target: "http://localhost:8001" }))
app.use(express.static("./static"))
https.createServer(credentials, app).listen(443);
// Redirect all HTTP traffic to HTTPS
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
pong.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http, {
path: "/pong/"
});
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
http.listen(8002, function(){
console.log('listening on *:8002');
});
index.html
<script src="/pong/socket.io.js"></script>
<script>
var socket = io({
// transports: ['websocket'], upgrade: false, (using for testing)
path:"/pong"
})
// ...
</script>
What I have currently comes from following the answer to this question:
Setting up multiple socket.io/node.js apps on an Apache server?
However in the firefox console I get a warning which reads:
Loading failed for the <script> with source “https://curlip.xyz/pong/socket.io.js”, followed by an error io is not defined. In the network tab getting socket.io.js is showing a 404.
So what I believe is happening is that because express is capturing the requests for /, socket.io cannot (for some reason) server socket.io.js. However when I changed / to /index.html and loaded that there was no change.
So I did some more research and came upon a solution. I opened the port 8002 on my EC2 so that I could poke around looking for socket.io.js.
Essentially what I found is socket.io.js was located at /pong/pong/socket.io.js because I set path in pong.js to "pong", which, in hindsight make sense, the proxy adds one "pong", while socket.io itself is capturing "/pong".
Knowing this I removed the path option in pong.js, so that socket.io.js can be found at /pong/socket.io/socket.io.js. I then made the client point to this by changing the script tag and path option in index.html.
pong.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
http.listen(8002, function(){
console.log('listening on *:8002');
});
index.html
<script src="/pong/socket.io/socket.io.js"></script>
var socket = io({
path:"/pong/socket.io/"
})
I'm using the node-http-proxy library to create a forward proxy server.
I eventually plan to use some middleware to modify the html code on the fly.
This is how my proxy server code looks like
var httpProxy = require('http-proxy')
httpProxy.createServer(function(req, res, proxy) {
var urlObj = url.parse(req.url);
console.log("actually proxying requests")
req.headers.host = urlObj.host;
req.url = urlObj.path;
proxy.proxyRequest(req, res, {
host : urlObj.host,
port : 80,
enable : { xforward: true }
});
}).listen(9000, function () {
console.log("Waiting for requests...");
});
Now I modify chrome's proxy setting, and enable web proxy server address as localhost:9000
However every time I visit a normal http website, my server crashes saying "Error: Must provide a proper URL as target"
I am new at nodejs, and I don't entirely understand what I'm doing wrong here?
To use a dynamic target, you should create a regular HTTP server that uses a proxy instance for which you can set the target dynamically (based on the incoming request).
A bare bones forwarding proxy:
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({});
http.createServer(function(req, res) {
proxy.web(req, res, { target: req.url });
}).listen(9000, () => {
console.log("Waiting for requests...");
});
Can anyone please explain what the router in options does in this code. I got this code from a blog. I am trying to implement node http-proxy.
var http = require('http'),
httpProxy = require('http-proxy');
//
//Leave out the hostnameOnly field this time, or set it to false...
//
var options = {
router: {
'domainone.com/appone': '127.0.0.1:9000',
'domainone.com/apptwo': '127.0.0.1:9001',
'domaintwo.net/differentapp': '127.0.0.1:9002'
}
}
//
//...and then pass in your options like last time.
//
var proxyServer = httpProxy.createServer(options).listen(80);
//
// ...and a simple http server to show us our request back.
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
The proxy library will take all incoming requests and attempt to match it with a rule in your router table. Assuming it finds a match, it will forward that request to the IP address associated with the DNS name you provided.
For example, requests going to domainone.com/appone will be forwarded to 127.0.0.1:9000
One problem that I see here is that you are listening on port 9000, and your first rule re-routes to 127.0.0.1:9000.
I am using http module in my project but most of my 'post' requests are blocked by postman.
I read it is a ssl issue,after some research i found another module named https.
Here is my current code.
var http = require('http');
var server = http.createServer(app);
Hei, make sure that the interceptor in Postman is off (it should be in the top, left to the "Sign in" button)
And related to https, as stated in Node.js v5.10.1 Documentation
HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module.
I used it once to make requests from my server to other servers over https (port 443).
btw, your code shouldn't work, try this
const http = require('http');
http.createServer( (request, response) => {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
and use http://127.0.0.1:8124 in Postman
..hoped it helped
const http = require('http');
http.createServer( function(request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(3000);
console.log('Server running at http://localhost:3000/');
The difference between HTTP and HTTPS is if you need to communicate with the servers over SSL, encrypting the communication using a certificate, you should use HTTPS, otherwise you should use HTTP, for example:
With HTTPS you can do something like that:
var https = require('https');
var options = {
key : fs.readFileSync(path.resolve(__dirname, '..', 'ssl', 'prd', 'cert.key')).toString(),
cert : fs.readFileSync(path.resolve(__dirname, '..', 'ssl', 'prd', 'cert.crt')).toString(),
};
var server = https.createServer(options, app);
server = server.listen(443, function() {
console.log("Listening " + server.address().port);
});
I have an application that uses websockets via socket.io. For my application I would like to use a separate HTTP server for serving the static content and JavaScript for my application. Therefore, I need to put a proxy in place.
I am using node-http-proxy. As a starting point I have my websockets app running on port 8081. I am using the following code to re-direct socket.io communications to this standalone server, while using express to serve the static content:
var http = require('http'),
httpProxy = require('http-proxy'),
express = require('express');
// create a server
var app = express();
var proxy = httpProxy.createProxyServer({ ws: true });
// proxy HTTP GET / POST
app.get('/socket.io/*', function(req, res) {
console.log("proxying GET request", req.url);
proxy.web(req, res, { target: 'http://localhost:8081'});
});
app.post('/socket.io/*', function(req, res) {
console.log("proxying POST request", req.url);
proxy.web(req, res, { target: 'http://localhost:8081'});
});
// Proxy websockets
app.on('upgrade', function (req, socket, head) {
console.log("proxying upgrade request", req.url);
proxy.ws(req, socket, head);
});
// serve static content
app.use('/', express.static(__dirname + "/public"));
app.listen(8080);
The above application works just fine, however, I can see that socket.io is no longer using websockets, it is instead falling back to XHR polling.
I can confirm that by looking at the logs from the proxy code:
proxying GET request /socket.io/1/?t=1391781619101
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294
proxying POST request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=1391781629
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294
Does anyone know how to proxy the web sockets communication? All the examples from node-http-proxy assume that you want to proxy all traffic, rather than proxying some and serving others.
Just stumbled upon your question, and I see that it is still not answered. Well, in case you are still looking for the solution...
The problem in your code is that app.listen(8080) is just syntactic sugar for
require('http').createServer(app).listen(8080)
while app itself is just a handler function, not an instance of httpServer (I personally believe that this feature should be removed from Express to avoid confusion).
Thus, your app.on('upgrade') is actually never used. You should instead write
var server = require('http').createServer(app);
server.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
server.listen(8080);
Hope, that helps.
Do you need both servers? If not you could use the same server for static files and to listen for socket connections:
// make the http server
var express = require('express'),
app = express(), server = require('http').createServer(app),
io;
// serve static content
server.use('/', express.static(__dirname + '/public'));
server.listen(8080);
// listen for socket connections
io = require('socket.io').listen(server);
// socket stuff here