Подтвердить что ты не робот

Ruby Net:: HTTP - после 301 переадресации

Мои пользователи представляют URL-адреса (для микширования на mixcloud.com), и мое приложение использует их для выполнения веб-запросов.

A хороший URL возвращает код состояния 200:

uri = URI.parse("http://www.mixcloud.com/ErolAlkan/hard-summer-mix/")
request = Net::HTTP.get_response(uri)(
#<Net::HTTPOK 200 OK readbody=true>

Но если вы забудете трейлинг-косую черту, тогда в противном случае хороший URL-адрес вернет 301:

uri = "http://www.mixcloud.com/ErolAlkan/hard-summer-mix"
#<Net::HTTPMovedPermanently 301 MOVED PERMANENTLY readbody=true> 

То же самое происходит с 404:

# bad path returns a 404
"http://www.mixcloud.com/bad/path/" 
# bad path minus trailing slash returns a 301
"http://www.mixcloud.com/bad/path"
  • Как я могу "развернуть" в 301, чтобы узнать, приведет ли он нас к действительному ресурсу или странице с ошибкой?
  • Есть ли инструмент, предоставляющий всесторонний обзор правил, которые могут применяться определенным доменом к их URL-адресам?
4b9b3361

Ответ 1

301 переадресации довольно распространены, если вы не вводите URL-адрес точно так, как этого требует веб-сервер. Они происходят гораздо чаще, чем вы думаете, вы просто обычно не замечаете их во время просмотра, потому что браузер делает все это автоматически для вас.

Приходят на ум две альтернативы:

1: используйте open-uri

open-uri обрабатывает перенаправления автоматически. Так что вам нужно всего лишь:

require 'open-uri' 
...
response = open('http://xyz...').read

2: Переадресация дескрипторов с помощью Net::HTTP

def get_response_with_redirect(uri)
   r = Net::HTTP.get_response(uri)
   if r.code == "301"
     r = Net::HTTP.get_response(URI.parse(r.header['location']))
   end
   r
end

Если вы хотите быть более умным, вы можете попытаться добавить или удалить отсутствующие обратные косые черты к URL-адресу, когда вы получите ответ 404. Вы можете сделать это, создав метод, подобный get_response_smart, который обрабатывает этот URL-адрес в дополнение к перенаправлению.

Ответ 2

Я не могу понять, как комментировать принятый ответ (этот вопрос может быть закрыт), но я должен отметить, что r.header теперь устарел, поэтому r.header['location'] следует заменить на r['location'] (per fooobar.com/questions/168741/...)

Ответ 3

rest-client следует перенаправления для запросов GET и HEAD без какой-либо дополнительной настройки. Он работает очень хорошо.

  • для кодов результатов между 200 и 207, возвращается RestClient:: Response
  • для результирующих кодов 301, 302 или 307 будет выполняться перенаправление, если запрос является GET или HEAD
  • для результирующего кода 303, будет выполняться перенаправление, и запрос преобразуется в GET

пример использования:

require 'rest-client'

RestClient.get 'http://example.com/resource'

rest-client README также дает пример следующих переадресаций с запросами POST:

begin
  RestClient.post('http://example.com/redirect', 'body')
rescue RestClient::MovedPermanently,
       RestClient::Found,
       RestClient::TemporaryRedirect => err
  err.response.follow_redirection
end

Ответ 4

Вот код, который я придумал (полученный из разных примеров), который выйдет из строя, если слишком много перенаправлений (обратите внимание, что secure_success является необязательным):

require "net/http"
require "uri"
class Net::HTTPResponse
  def ensure_success
    unless kind_of? Net::HTTPSuccess
      warn "Request failed with HTTP #{@code}"
      each_header do |h,v|
        warn "#{h} => #{v}"
      end
      abort
    end
  end
end
def do_request(uri_string)
  response = nil
  tries = 0
  loop do
    uri = URI.parse(uri_string)
    http = Net::HTTP.new(uri.host, uri.port)
    request = Net::HTTP::Get.new(uri.request_uri)
    response = http.request(request)
    uri_string = response['location'] if response['location']
    unless response.kind_of? Net::HTTPRedirection
      response.ensure_success
      break
    end
    if tries == 10
      puts "Timing out after 10 tries"
      break
    end
    tries += 1
  end
  response
end

Ответ 5

Не уверен, что кто-то ищет это точное решение, но если вы пытаетесь загрузить изображение http/https и храните его в переменной

require 'open_uri_redirections'

require 'net/https'

web_contents  = open('file_url_goes_here', :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, :allow_redirections => :all) {|f| f.read }
puts web_contents