I am using a Node Express app to proxy AJAX requests to a REST API because the API doesn't support CORS or JSONP yet. The Node app is running on Heroku. We have a reverse proxy setup in front of the Heroku app so that we can mount it anywhere we want in our domain (i.e., it's trivial to move from ourdomain.com/app to ourdomain.com/stuff/app).
The AJAX requests work great when I access the Heroku app directly. However, when I try to access the app through the reverse proxy, the AJAX requests fail with a connection timeout.
The web client makes an AJAX request to the Heroku app via the reverse proxy
Web Client --> Reverse Proxy --> Heroku app
Then the requests get proxied to the API server which also sits behind our reverse proxy
Heroku app --> Reverse Proxy --> API Server
The requests don't fail if the app is accessed directly, thus skipping the reverse proxy the first time:
Web client --> Heroku app --> Reverse Proxy --> API Server
Here's an example of how I originally tried to proxy the requests. It fails when the AJAX request goes through the reverse proxy to the Heroku app but works if the app is accessed directly.
app.get('/proxy/*', function(req, res){
var proxyURL = getProxyUrl(req);
req.pipe(request.get(proxyURL)).pipe(res);
});
I was able fix the problem for GET requests with the following:
app.get('/proxy/*', function(req, res){
var proxyURL = getProxyUrl(req);
request({
url: proxyURL ,
headers: {
accept: req.headers.accept,
authorization: req.headers.authorization
}
}).pipe(res);
});
I also need to proxy POST and PUT which aren't as easy. Here's what I tried for POST; it works when it doesn't handle requests that came through the reverse proxy.
app.post('/proxy/*', function(req, res){
var rawBody = '';
req.setEncoding('utf8');
req.on('data', function(chunk) {
rawBody += chunk;
});
req.on('end', function(){
var proxyURL = getProxyUrl(req);
request.post({
url: proxyURL,
body: rawBody,
headers: {
'content-type': req.headers['content-type'],
'authorization': req.headers.authorization
}
}, function(e, r, body){
res.send(body);
});
});
});