node.jsproxyexpressreverse-proxy

Proxy with express.js


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/http-party/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.


Solution

  • You want to use http.request to create a similar request to the remote API and return its response.

    Something like this:

    const http = require('http');
    // or use import http from 'http';
    
    
    /* your app config here */
    
    app.post('/api/BLABLA', (oreq, ores) => {
      const 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: oreq.headers,
      };
    
      const creq = http
        .request(options, pres => {
          // set encoding
          pres.setEncoding('utf8');
    
          // set http status code based on proxied response
          ores.writeHead(pres.statusCode);
    
          // wait for data
          pres.on('data', chunk => {
            ores.write(chunk);
          });
    
          pres.on('close', () => {
            // closed, let's end client request as well
            ores.end();
          });
    
          pres.on('end', () => {
            // finished, let's finish client request as well
            ores.end();
          });
        })
        .on('error', e => {
          // we got an error
          console.log(e.message);
          try {
            // attempt to set error message and http status
            ores.writeHead(500);
            ores.write(e.message);
          } catch (e) {
            // ignore
          }
          ores.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.