How to do 301 Redirects #37

Closed
emotely opened this Issue Apr 24, 2011 · 17 comments

Comments

Projects
None yet
@ghost

ghost commented Apr 24, 2011

I'm trying to remove the www. requests to point them to the canonical non www. urls. This is the make sure copy pasted urls point to one domain and thus not divide up my Google Page Rank juice across the two domains.

Owner

indexzero commented Apr 24, 2011

node-http-proxy doesn't support 301 redirects yet, but I will leave this issue as this is something we want to address in future versions.

@ghost

ghost commented Apr 24, 2011

Thanks for the quick answer. I guess I could put the redirect logic into the actual server that the domain is served on. I'll post my solution to that when I get it working. It will help those that have the same issue.

For reference here's the solution I ended up using. Note: I'm using express so it's express specific code:

app.configure(function(){
  // Forward www.emotely.com to emotely.com
  app.use(function(req,res,next){
    if(req.headers.host=="www.emotely.com"){
      res.writeHead(301, {'Location':'http://emotely.com'+req.url, 'Expires': (new Date).toGMTString()});
      res.end();
    }
    else{
      next();
    }
  });
});

But what happens if i don't know the URL redirect? thanks

Now http-proxy supports connect middleware you can use no-www

var http = require('http'),
httpProxy = require('http-proxy');

var options = {
hostnameOnly: true,
router: {
'example.com': '127.0.0.1:8001'
}
}

var proxyServer = httpProxy.createServer(
require('connect-no-www')(false),
options
);

proxyServer.listen(80);

I got this working, here's my code, inserted in the middle of the boilerplate http+websockets example:
https://gist.github.com/konklone/5006662

pajtai commented Jun 18, 2014

here's a generic one - modified from @francoislaberge example - I use as the first piece of middleware in my express app:

express.use(function(req,res,next){
        var host = req.get('host');
        if(/^www\./.test(host)){
            host = host.substring(4, host.length);
            res.writeHead(301, {'Location':req.protocol + '://' + host + req.originalUrl,
                'Expires': new Date().toGMTString()});
            res.end();
        } else {
            next();
        }
    });

You could reverse it just as easily making sure that host always starts with www.

q2dg commented Aug 18, 2014

Http-proxy doesn't still support 301 Redirects??
So...this code won't redirect to Google, really??

var url = require("url")
var http = require("http")
var httpProxy = require("http-proxy")
var proxy = httpProxy.createProxyServer()
http.createServer(function(req, res) {
proxy.web(req, res, { target: "http://www.google.com", headers: { host: "www.google.com"} })
}).listen(4000)

I don't find very useful a proxy like this, sincerely.
But thanks for your work

Owner

jcrugzz commented Aug 18, 2014

@q2dg i think you are mistaking terminology. Your code correctly proxies any request to the server to google.com. This is not the same as redirecting to google as the traffic is still going through your server.

q2dg commented Aug 18, 2014

Well, maybe I haven't stated the problem incorrectly, sorry.

If you try my above code (having configured proxy settings in a browser pointing to it) you will see it doesn't work: browser shows a "restarted connection" error. But if you change "www.google.com" by another URL which doesn't suffer from redirection (for instance, "www.linux.com"), it does work (withouth changing browser's direction bar, but it doesn't matter). At least, this is what happens in Spain, where "www.google.com" is automatically redirected to "www.google.es".

It's the only explanation I have: http-proxy doesn't handle 3xx responses, like official http.get() method either. But, of course, I can be wrong.

Owner

jcrugzz commented Aug 19, 2014

@q2dg ok well this does seem plausible. This is something that should be handled in some manner. If you can come up with a good failing test case (integrated into the actual tests) I can take a stab at implementing it

q2dg commented Aug 21, 2014

Ok, I will try. Thanks!!

+1 to add redirection support. We could have the following simple format to indicate whether the request should be redirected to proxies.

proxy: {
    router: {
        // This is what http-proxy already supports, i.e. proxying.
        'domain.com': 'http://127.0.0.1:10088',
        // To support redirect we could provide an object:
        'domain2.com': {
            redirect_host: 'http://domain.com'
        }
    }
}

If the http-proxy notices the redirect_host property, then it will redirect instead of proxying.

Contributor

Rush commented Oct 30, 2014

I think this is scope of a different project. In fact http-master is a module which tries to do intelligent things around the http-proxy, including redirects and serving a static file directory.

I have just implemented the redirection as follows without changing a code in http-proxy.

proxy: {
    router: {
        // This is what http-proxy already supports, i.e. proxying.
        'domain.com': 'http://127.0.0.1:10088',
        // To support redirect we could provide an object:
        'domain2.com': {
            redirect_host: 'http://domain.com',
            // `307` status code indicates that the request
            // should be repeated using the same method and post data
            // and that the redirection is temporary. The future
            // requests should still use the original URI.
            // In contrast to how 302 was historically implemented,
            // the request method is not allowed to be changed when
            // reissuing the original request. For instance, a POST
            // request should be repeated using another POST request.
            // `308` status code indicates that the request
            // should be repeated using the same method and post data
            // and that the redirection is permanent unlike `307`.
            status: 308
        }
    }
}

Then in the app.js code I have the following:

server = http.createServer(function (req, res) {
    var host = req.headers.host,
            ix = host.indexOf(':' + conf.port);

    // In case hosts include the port as well like `:80`.
    ~ix && (host = host.substring(0, ix));

    if (proxy.router.hasOwnProperty(host)) {
        host = proxy.router[host];

        if (typeof host == 'object' && host.redirect_host) {
            res.writeHead(host.status || 308, {
                Location: host.redirect_host + req.url
            });

            res.end();
        } else {
            proxy.web(req, res, {
                target: host
            });
        }
    } else {
        res.writeHead(404, {
            'Content-Type': 'text/plain'
        });

        res.end('No server is listening for this domain.');
    }
});

Comments are welcome.

Owner

jcrugzz commented Oct 30, 2015

This should technically be supported with https://github.com/nodejitsu/node-http-proxy/blob/master/lib/http-proxy/passes/web-outgoing.js#L49-L70. If not please open a new issue.

@jcrugzz jcrugzz closed this Oct 30, 2015

How about support for autoProtocolRewrite, as the option protocolRewrite doesn't look at the request protocol to rewrite location returned from the target proxy. So if if I want to support both https and http on my entry site, the only option right now is to write a custom proxyRes handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment