14

How do I take this URL http://t.co/yjgxz5Y and get the destination URL which is http://nickstraffictricks.com/4856_how-to-rank-1-in-google/

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Nick
  • 241
  • 3
  • 5

4 Answers4

24
require 'net/http'
require 'uri'

Net::HTTP.get_response(URI.parse('http://t.co/yjgxz5Y'))['location']
# => "http://nickstraffictricks.com/4856_how-to-rank-1-in-google/" 
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • 2
    According to the docs, Net::HTTP doesn't do recursive redirects, which is necessary if a redirect gets redirected. This looks like it would only handle the first one. – the Tin Man Apr 03 '11 at 23:17
  • 1
    True. You would need a loop around that. But anyway, this is how you would follow a redirect in Ruby, and I believe that answers the question. – Mladen Jablanović Apr 04 '11 at 06:32
8

I've used open-uri for this, because it's nice and simple. It will retrieve the page, but will also follow multiple redirects:

require 'open-uri'

final_uri = ''
open('http://t.co/yjgxz5Y') do |h|
  final_uri = h.base_uri
end
final_uri # => #<URI::HTTP:0x00000100851050 URL:http://nickstraffictricks.com/4856_how-to-rank-1-in-google/>

The docs show a nice example for using the lower-level Net::HTTP to handle redirects.

require 'net/http'
require 'uri'

def fetch(uri_str, limit = 10)
  # You should choose better exception.
  raise ArgumentError, 'HTTP redirect too deep' if limit == 0

  response = Net::HTTP.get_response(URI.parse(uri_str))
  case response
  when Net::HTTPSuccess     then response
  when Net::HTTPRedirection then fetch(response['location'], limit - 1)
  else
    response.error!
  end
end

puts fetch('http://www.ruby-lang.org')

Of course this all breaks down if the page isn't using a HTTP redirect. A lot of sites use meta-redirects, which you have to handle by retrieving the URL from the meta tag, but that's a different question.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Thanks! very helpful.. doing h.base_uri.to_s will render destination url. – k_ssup Jan 24 '13 at 20:06
  • I think you can skip the use of block and just call `open(url).base_uri` – lulalala Nov 27 '13 at 04:14
  • The `Net::HTTP` version should be the accepted answer, because it handles SSL as well as recursive redirects (most examples seem to only handle one or the other). Well done! – Abe Voelker Apr 04 '15 at 03:43
3

For resolving redirects you should use a HEAD request to avoid downloading the whole response body (imagine resolving a URL to an audio or video file).

Working example using the Faraday gem:

require 'faraday'
require 'faraday_middleware'

def resolve_redirects(url)
    response = fetch_response(url, method: :head)
    if response
        return response.to_hash[:url].to_s
    else
        return nil
    end
end

def fetch_response(url, method: :get)
    conn = Faraday.new do |b|
        b.use FaradayMiddleware::FollowRedirects;
        b.adapter :net_http
    end
    return conn.send method, url
rescue Faraday::Error, Faraday::Error::ConnectionFailed => e
    return nil
end

puts resolve_redirects("http://cre.fm/feed/m4a") # http://feeds.feedburner.com/cre-podcast
ericteubert
  • 4,531
  • 3
  • 31
  • 35
1

You would have to follow the redirect. I think that would help :

http://shadow-file.blogspot.com/2009/03/handling-http-redirection-in-ruby.html

Spyros
  • 46,820
  • 25
  • 86
  • 129
  • 1
    Not technically correct. You don't need to "follow" the redirect, you merely need to read the Location header that was sent to cause the redirect, as in Mladen Jablanović's answer. – jemminger Apr 03 '11 at 21:15
  • 1
    It's possible to have a redirection be redirected. Unless the underlying code handles that automatically, which it won't using Net::HTTP, then the redirects have to be followed too until you either decide the redirections are too deep, or they finally resolve at the final URL. The particular page linked to is more convoluted than the example in Net::HTTP's docs. – the Tin Man Apr 03 '11 at 23:14