2011-04-03 255 views

回答

1

您将不得不关注重定向。我认为,这将有助于:

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

+1

技术上不正确。你不需要“关注”重定向,你只需要读取发送来重定向的位置标题,就像在MladenJablanović的回答中一样。 – jemminger 2011-04-03 21:15:41

+0

你是对的,我没有正确说明:) – Spyros 2011-04-03 22:27:52

+1

有可能重定向被重定向。除非底层代码自动处理它,它不会使用Net :: HTTP,否则必须遵循重定向,直到您确定重定向太深,或者最终在最终URL处终止。链接到的特定页面比Net :: HTTP文档中的示例更加复杂。 – 2011-04-03 23:14:53

23
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/" 
+2

根据文档,Net :: HTTP不会执行递归重定向,如果重定向被重定向,这是必需的。这看起来像只能处理第一个。 – 2011-04-03 23:17:02

+1

是的。你需要一个循环。但无论如何,这是你如何遵循Ruby中的重定向,我相信这回答了这个问题。 – 2011-04-04 06:32:06

8

我用open-uri对于这一点,因为它的简单好用。它将检索页面,也将遵循多重定向:

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/> 

该文档显示一个很好的例子使用较低级别的Net::HTTP处理重定向。

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') 

当然,如果页面没有使用HTTP重定向,这一切都会崩溃。很多网站使用元重定向,您必须通过从元标记中检索URL来处理这些重定向,但这是一个不同的问题。

+0

谢谢!非常有帮助..做h.base_uri.to_s将呈现目标网址。 – KG2289 2013-01-24 20:06:51

+0

我认为你可以跳过块的使用,只需调用'open(url).base_uri' – lulalala 2013-11-27 04:14:57

+0

'Net :: HTTP'版本应该是可接受的答案,因为它处理SSL以及递归重定向(大多数示例似乎只处理一个或另一个)。做得好! – 2015-04-04 03:43:39

3

为了解决重定向问题,您应该使用HEAD请求来避免下载整个响应主体(想象一下将一个URL解析为音频或视频文件)。使用法拉第宝石

工作实施例:

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