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

Как читать только x число байтов тела с помощью Net:: HTTP?

Похоже, что методы Ruby Net:: HTTP - это все или ничего, когда дело доходит до чтения веб-страницы. Как я могу читать, скажем, только первые 100 байт тела?

Я пытаюсь прочитать с сервера содержимого, который возвращает короткое сообщение об ошибке в тексте ответа, если запрошенный файл недоступен. Мне нужно прочитать достаточно тела, чтобы определить, есть ли файл. Файлы огромны, поэтому я не хочу, чтобы весь тело просто проверял, доступен ли файл.

4b9b3361

Ответ 1

Не следует ли использовать HTTP-запрос HEAD (метод Ruby Net::HTTP::Head), чтобы узнать, существует ли этот ресурс, и продолжать действовать только в том случае, если вы получаете ответ 2xx или 3xx? Это предполагает, что ваш сервер настроен на возврат кода ошибки 4xx, если документ недоступен. Я бы сказал, что это было правильное решение.

Альтернативой является запрос заголовка HTTP и просмотр значения заголовка content-length в результате: если ваш сервер настроен правильно, вы можете легко определить разницу в длине между коротким сообщением и длинным документом, Другая альтернатива: установите поле заголовка content-range в запросе (который снова предполагает, что сервер ведет себя корректно WRT спецификацию HTTP).

Я не думаю, что решение проблемы в клиенте после того, как вы отправили запрос GET, - это путь: к тому времени сеть сделала тяжелую работу, и вы действительно не будете экономить потраченные ресурсы.

Ссылка: определения заголовков HTTP

Ответ 2

Это старый поток, но вопрос о том, как читать только часть файла через HTTP в Ruby, по-прежнему остается в основном без ответа по моим исследованиям. Вот решение, с которым я столкнулся с попыткой обезглавливать Net:: HTTP:

require 'net/http'

# provide access to the actual socket
class Net::HTTPResponse
  attr_reader :socket
end

uri = URI("http://www.example.com/path/to/file")
begin
  Net::HTTP.start(uri.host, uri.port) do |http|
    request = Net::HTTP::Get.new(uri.request_uri)
    # calling request with a block prevents body from being read
    http.request(request) do |response|
      # do whatever limited reading you want to do with the socket
      x = response.socket.read(100);
      # be sure to call finish before exiting the block
      http.finish
    end
  end
rescue IOError
  # ignore
end

Спасение улавливает IOError, который вызывается, когда вы вызываете HTTP.finish преждевременно.

FYI, сокет внутри объекта HTTPResponse не является истинным IO объектом (он является внутренним классом под названием BufferedIO), но довольно легко для обезьяны-патча, который тоже имитирует IO методы, которые вам нужны. Например, другой библиотеке, которую я использовал (exifr), нужен метод readchar, который легко добавить:

class Net::BufferedIO
  def readchar
    read(1)[0].ord
  end
end

Ответ 3

Я хотел сделать это один раз, и единственное, что я мог подумать, - это обезьяна, исправляющая методы Net::HTTP#read_body и Net::HTTP#read_body_0 для принятия параметра длины, а затем в первом просто передайте параметр длины в read_body_0, где вы можете читать только столько, сколько длина байтов.

Ответ 4

Вы уверены, что сервер содержимого возвращает только короткую страницу с ошибкой?

Не устанавливает ли он HTTPResponse что-то подходящее, например, 404. В этом случае вы можете уловить производное исключение HTTPClientError (скорее всего HTTPNotFound), которое возникает при доступе к Net::HTTP.value().

Если вы получите сообщение об ошибке, то ваш файл не будет, если вы получите 200, файл начнет загружаться, и вы можете закрыть соединение.

Ответ 5

Чтобы прочитать тело HTTP-запроса в кусках, вам нужно использовать Net::HTTPResponse#read_body следующим образом:

http.request_get('/large_resource') do |response|
  response.read_body do |segment|
    print segment
  end
end

Ответ 6

Вы не можете. Но зачем вам это нужно? Конечно, если страница просто говорит, что файл недоступен, то это не будет огромная страница (т.е. По определению, файл там не будет)?