node-http-proxy icon indicating copy to clipboard operation
node-http-proxy copied to clipboard

Document `forward` vs. `target`

Open ahamid opened this issue 10 years ago • 9 comments
trafficstars

After reading the docs and examples, the purpose and distinction between forward and target is still not clear to me (including forward-and-target-proxy.js example - I can't tell what this is actually demonstrating). After implementing a very simple single-step target proxy behind Express, I wanted to place a transparent forward proxy in between Node and backend server in order to cache some large, expensive API requests. I was not successful with any permutation of forward or target options. My intuition was that target would be used to "fix up" the outbound request (setupOutgoing), while forward would be the immediate server to hand off to (the local caching proxy). It appears that changeOrigin will use the forward host, not the target host. This is likely due to logic in stream and setupOutgoing that appears to modify the request for both cases. I'm not sure I understand the precedence of the piping. Also forward will not convert a relative path request to an absolute URL request required by an upstream transparent HTTP proxy.

It would be nice to have a some more docs on how to use forward and target in combination or separately, and whether handoff to transparent proxy is supported out of the box (e.g. inference from combination of forward and target would be nice).

I managed to manually perform these fixups when in 'transparent handoff' mode as advised on StackOverflow:

opts = target: remoteServer

if process.argv[2]?
  localProxy = process.argv[2]
  opts.forward = localProxy
  opts.toProxy = true
  opts.prependPath = false # fix it up ourselves

console.log "Proxying #{apiRoot} to #{remoteServer}" + (if localProxy? then " via #{localProxy}" else "")

proxy = httpProxy.createProxyServer opts
app.use apiRoot, (req, res, next) ->
  console.log "Proxying: #{req.method} #{req.path} to #{remoteServer}"
  console.log "Original URL #{req.url}"
  console.log "Original Host #{req.headers.host}"
  # explicitly fix up host and request url if forwarding to local proxy
  if localProxy?
    remote = url.parse(remoteServer)
    incoming = url.parse(req.url)
    req.headers.host  = remote.host
    # update the host and path to match remote target
    incoming.protocol = remote.protocol
    incoming.host = remote.host
    incoming.pathname = remote.pathname + incoming.pathname
    req.url = url.format(incoming)
    console.log "Outbound Host #{req.headers.host}"
    console.log "Outbound URL #{req.url}"

    proxy.web req, res, (e) ->
      console.log e

ahamid avatar Feb 11 '15 18:02 ahamid

Citation from damonmcminn's an answer;

http.createServer(function(req, res) {
  /* target NOT forward
  *  target === final server to receive request
  *  forward === another proxy server to pass request through
  */
  var options = {
    target: targets[req.headers.host]
  };
  proxy.web(req, res, options, errorCallback); // errorCallback is optional
}).listen(1443);

efkan avatar Apr 07 '15 06:04 efkan

+1, the documentation should definitely explain the difference between target and forward.

eladnava avatar Dec 01 '15 12:12 eladnava

+1 on putting this:

  *  target === final server to receive request
  *  forward === another proxy server to pass request through

in the readme.

prust avatar Jan 20 '16 21:01 prust

https://github.com/nodejitsu/node-http-proxy/issues/917 yuuup, still really unclear and missing from the doc.

michahell avatar Jul 31 '17 14:07 michahell

I had to look to find this post, it's istll unclear in the doc right now.

NoxWorld258 avatar Dec 12 '17 15:12 NoxWorld258

it's 2018.9.12

chocking avatar Sep 12 '18 07:09 chocking

It seems "forward" does not send the response back to the requesting side. In fact, docs says exactly that:

  /**
   * Does the actual proxying. If `forward` is enabled fires up
   * a ForwardStream, same happens for ProxyStream. **The request
   * just dies otherwise.**
   *
   * @param {ClientRequest} Req Request object
   * @param {IncomingMessage} Res Response object
   * @param {Object} Options Config object passed to the proxy
   *
   * @api private
   */

  stream: function stream(req, res, options, _, server, clb) {

Note, the The request just dies otherwise.

Source code follows the docs (from /node-http-proxy/lib/http-proxy/passes/web-incoming.js):

    if(options.forward) {
      // If forward enable, so just pipe the request
      ...
      if(!options.target) { return res.end(); }
    }

Note, the return res.end(). The empty response is sent back.

It seems, when one need to forward the request to another proxy, that proxy should still be specified in the "target" field. The "changeOrigin" should be set to "false". The "toProxy" option didn't make any difference in my experiments, but keeping it in "true" did not harm.

The intention of the "forward" option is still very much unclear.

canonic-epicure avatar Sep 17 '18 15:09 canonic-epicure

2020.05.29 it's still unclear

gugegev5 avatar May 29 '20 06:05 gugegev5

I believe the functionality of forward was accurately described in the README of the previous incarnation of node-http-proxy, see https://github.com/http-party/node-http-proxy/tree/840f6d8d29dffc11d3726123c2d400940ca2bdda#proxy-requests-with-an-additional-forward-proxy

Proxy requests with an additional forward proxy

Sometimes in addition to a reverse proxy, you may want your front-facing server to forward traffic to another location. For example, if you wanted to load test your staging environment. This is possible when using node-http-proxy using similar JSON-based configuration to a proxy table: …

It seems when the entire project was rewritten in https://github.com/http-party/node-http-proxy/pull/552, the functionality was preserved but the documentation went away.

jonathanperret avatar Sep 07 '22 11:09 jonathanperret