To avoid same-domain AJAX issues, I want my node.js web server to forward all requests from URL /api/BLABLA
to another server, for example other_domain.com:3000/BLABLA
, and return to user the same thing that this remote server returned, transparently.
All other URLs (beside /api/*
) are to be served directly, no proxying.
How do I achieve this with node.js + express.js? Can you give a simple code example?
(both the web server and the remote 3000
server are under my control, both running node.js with express.js)
So far I found this https://github.com/nodejitsu/node-http-proxy/ , but reading the documentation there didn't make me any wiser. I ended up with
var proxy = new httpProxy.RoutingProxy();
app.all("/api/*", function(req, res) {
console.log("old request url " + req.url)
req.url = '/' + req.url.split('/').slice(2).join('/'); // remove the '/api' part
console.log("new request url " + req.url)
proxy.proxyRequest(req, res, {
host: "other_domain.com",
port: 3000
});
});
but nothing is returned to the original web server (or to the end user), so no luck.
I did something similar but I used request instead:
var request = require('request');
app.get('/', function(req,res) {
//modify the url in any way you want
var newurl = 'http://google.com/';
request(newurl).pipe(res);
});
I hope this helps, took me a while to realize that I could do this :)
To extend trigoman's answer (full credits to him) to work with POST (could also make work with PUT etc):
app.use('/api', function(req, res) {
var url = 'YOUR_API_BASE_URL'+ req.url;
var r = null;
if(req.method === 'POST') {
r = request.post({uri: url, json: req.body});
} else {
r = request(url);
}
req.pipe(r).pipe(res);
});
You want to use http.request
to create a similar request to the remote API and return its response.
Something like this:
var http = require('http');
/* your app config here */
app.post('/api/BLABLA', function(req, res) {
var options = {
// host to forward to
host: 'www.google.com',
// port to forward to
port: 80,
// path to forward to
path: '/api/BLABLA',
// request method
method: 'POST',
// headers to send
headers: req.headers
};
var creq = http.request(options, function(cres) {
// set encoding
cres.setEncoding('utf8');
// wait for data
cres.on('data', function(chunk){
res.write(chunk);
});
cres.on('close', function(){
// closed, let's end client request as well
res.writeHead(cres.statusCode);
res.end();
});
cres.on('end', function(){
// finished, let's finish client request as well
res.writeHead(cres.statusCode);
res.end();
});
}).on('error', function(e) {
// we got an error, return 500 error to client and log error
console.log(e.message);
res.writeHead(500);
res.end();
});
creq.end();
});
Notice: I haven't really tried the above, so it might contain parse errors hopefully this will give you a hint as to how to get it to work.
I've created a extremely simple module that does exactly this: https://github.com/koppelaar/auth-proxy
Ok, here's a ready-to-copy-paste answer using the require('request') npm module and an environment variable *instead of an hardcoded proxy):
coffeescript
app.use (req, res, next) ->
method = req.method.toLowerCase()
switch method
when "get" then r = request.get {uri: process.env.PROXY_URL+req.url, json: req.body}
when "put" then r = request.put {uri: process.env.PROXY_URL+req.url, json: req.body}
when "post" then r = request.post {uri: process.env.PROXY_URL+req.url, json: req.body}
when "delete" then r = request.del {uri: process.env.PROXY_URL+req.url, json: req.body}
else return res.send("invalid method")
req.pipe(r).pipe(res)
javascript:
app.use(function(req, res, next) {
var method, r;
method = req.method.toLowerCase();
switch (method) {
case "get":
r = request.get({
uri: process.env.PROXY_URL + req.url,
json: req.body
});
break;
case "put":
r = request.put({
uri: process.env.PROXY_URL + req.url,
json: req.body
});
break;
case "post":
r = request.post({
uri: process.env.PROXY_URL + req.url,
json: req.body
});
break;
case "delete":
r = request.del({
uri: process.env.PROXY_URL + req.url,
json: req.body
});
break;
default:
return res.send("invalid method");
}
return req.pipe(r).pipe(res);
});