class Net::HTTPSession
Класс Net::HTTP предоставляет обширную библиотеку, реализующую клиент в модели клиент-сервер, использующей протокол запрос-ответ HTTP. Сведения об HTTP см. в следующих источниках:
Об этих примерах
В примерах предполагается, что был подключен net/http (который также подключает uri):
require 'net/http'
Во многих примерах кода используются следующие демонстрационные веб-сайты:
В некоторых примерах также предполагается, что определены следующие переменные:
uri = URI('https://jsonplaceholder.typicode.com/')
uri.freeze # Examples may not modify.
hostname = uri.hostname # => "jsonplaceholder.typicode.com"
path = uri.path # => "/"
port = uri.port # => 443
Поэтому демонстрационные запросы можно записывать так:
Net::HTTP.get(uri)
Net::HTTP.get(hostname, '/index.html')
Net::HTTP.start(hostname) do |http|
http.get('/todos/1')
http.get('/todos/2')
end
В примере, где требуется изменить URI, сначала создаётся копия uri, а затем изменяется копия:
_uri = uri.dup _uri.path = '/todos/1'
Стратегии
-
Если вам нужно выполнить всего несколько GET-запросов, рассмотрите возможность использования
OpenURI. -
Если вам нужно выполнить всего несколько запросов любого типа, рассмотрите возможность использования различных удобных методов-одиночек этого класса. Каждый из следующих методов автоматически начинает и завершает сеанс, отправляющий один запрос:
# Return string response body. Net::HTTP.get(hostname, path) Net::HTTP.get(uri) # Write string response body to $stdout. Net::HTTP.get_print(hostname, path) Net::HTTP.get_print(uri) # Return response as Net::HTTPResponse object. Net::HTTP.get_response(hostname, path) Net::HTTP.get_response(uri) data = '{"title": "foo", "body": "bar", "userId": 1}' Net::HTTP.post(uri, data) params = {title: 'foo', body: 'bar', userId: 1} Net::HTTP.post_form(uri, params) data = '{"title": "foo", "body": "bar", "userId": 1}' Net::HTTP.put(uri, data) -
Если важна производительность, рассмотрите возможность использования сеансов, снижающих накладные расходы на запросы. В этом сеансе выполняется несколько запросов с использованием методов HTTP и методов WebDAV:
Net::HTTP.start(hostname) do |http| # Session started automatically before block execution. http.get(path) http.head(path) body = 'Some text' http.post(path, body) # Can also have a block. http.put(path, body) http.delete(path) http.options(path) http.trace(path) http.patch(path, body) # Can also have a block. http.copy(path) http.lock(path, body) http.mkcol(path, body) http.move(path) http.propfind(path, body) http.proppatch(path, body) http.unlock(path, body) # Session finished automatically at block exit. end
Упомянутые выше методы являются удобными методами, которые благодаря небольшому числу аргументов обеспечивают минимальный контроль над запросами. Для более широкого контроля рассмотрите возможность использования объектов запросов.
URI
В интернете URI (универсальный идентификатор ресурса) — это строка, идентифицирующая определённый ресурс. Она состоит из некоторых или всех следующих частей: схема, имя узла, путь, запрос и фрагмент; см. синтаксис URI.
Объект Ruby URI::Generic представляет интернет-URI. Он предоставляет, помимо прочего, методы scheme, hostname, path, query и fragment.
Схемы
Интернет-URI имеет схему.
В Net::HTTP поддерживаются две схемы: 'https' и 'http':
uri.scheme # => "https"
URI('http://example.com').scheme # => "http"
Имена узлов
Имя узла идентифицирует сервер (узел), которому можно отправлять запросы:
hostname = uri.hostname # => "jsonplaceholder.typicode.com" Net::HTTP.start(hostname) do |http| # Some HTTP stuff. end
Пути
Путь, относящийся к конкретному узлу, идентифицирует ресурс на этом узле:
_uri = uri.dup _uri.path = '/todos/1' hostname = _uri.hostname path = _uri.path Net::HTTP.get(hostname, path)
Запросы
Запрос, относящийся к конкретному узлу, добавляет к URI пары имя/значение:
_uri = uri.dup
params = {userId: 1, completed: false}
_uri.query = URI.encode_www_form(params)
_uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com?userId=1&completed=false>
Net::HTTP.get(_uri)
Фрагменты
Фрагмент URI не влияет на Net::HTTP; возвращаются одни и те же данные независимо от того, включён ли фрагмент.
Заголовки запросов
Заголовки запросов можно использовать для передачи узлу дополнительной информации, подобно аргументам, передаваемым при вызове метода; каждый заголовок представляет собой пару имя/значение.
Каждый из методов Net::HTTP, отправляющих запрос узлу, имеет необязательный аргумент headers, в котором заголовки задаются в виде хеша пар имя поля/значение:
headers = {Accept: 'application/json', Connection: 'Keep-Alive'}
Net::HTTP.get(uri, headers)
Списки стандартных и часто используемых полей запроса см. в разделе Поля запроса. Узел также может принимать другие пользовательские поля.
Сеансы HTTP
Сеанс — это соединение между сервером (узлом) и клиентом, которое:
-
Начинается методом экземпляра
Net::HTTP#start. -
Может содержать любое количество запросов.
-
Завершается методом экземпляра
Net::HTTP#finish.
Примеры сеансов см. в разделе Стратегии.
Сеанс с помощью Net::HTTP.start
Если вам нужно выполнить множество запросов к одному узлу (и порту), рассмотрите возможность использования метода-одиночки Net::HTTP.start с блоком; метод автоматически управляет сеансом следующим образом:
В блоке можно использовать следующие методы экземпляра, каждый из которых отправляет один запрос:
-
-
get,request_get: GET. -
head,request_head: HEAD. -
post,request_post: POST. -
delete: DELETE. -
options: OPTIONS. -
trace: TRACE. -
patch: PATCH.
-
Сеанс с помощью Net::HTTP.start и Net::HTTP.finish
Сеанс можно управлять вручную с помощью методов start и finish:
http = Net::HTTP.new(hostname)
http.start
http.get('/todos/1')
http.get('/todos/2')
http.delete('/posts/1')
http.finish # Needed to free resources.
Сеанс с одним запросом
Некоторые удобные методы автоматически управляют сеансом следующим образом:
-
Создают объект HTTP.
-
Начинают сеанс.
-
Отправляют один запрос.
-
Завершают сеанс.
-
Уничтожают объект.
Методы, отправляющие GET-запросы:
-
::get: возвращает строку тела ответа. -
::get_print: записывает строку тела ответа в $stdout. -
::get_response: возвращает объектNet::HTTPResponse.
Методы, отправляющие POST-запросы:
-
::post: отправляет данные узлу. -
::post_form: отправляет узлу данные формы.
Запросы и ответы HTTP
Многие из описанных выше методов являются удобными методами: каждый из них отправляет запрос и возвращает строку, не используя напрямую объекты Net::HTTPRequest и Net::HTTPResponse.
Однако можно напрямую создать объект запроса, отправить запрос и получить объект ответа; см.:
Обработка перенаправлений
Каждый возвращаемый ответ является экземпляром подкласса Net::HTTPResponse. См. иерархию классов ответов.
В частности, класс Net::HTTPRedirection является родительским для всех классов перенаправлений. Это позволяет составить оператор case для правильной обработки перенаправлений:
def fetch(uri, limit = 10)
# You should choose a better exception.
raise ArgumentError, 'Too many HTTP redirects' if limit == 0
res = Net::HTTP.get_response(URI(uri))
case res
when Net::HTTPSuccess # Any success class.
res
when Net::HTTPRedirection # Any redirection class.
location = res['Location']
warn "Redirected to #{location}"
fetch(location, limit - 1)
else # Any other class.
res.value
end
end
fetch(uri)
Базовая аутентификация
Базовая аутентификация выполняется в соответствии с RFC2617:
req = Net::HTTP::Get.new(uri)
req.basic_auth('user', 'pass')
res = Net::HTTP.start(hostname) do |http|
http.request(req)
end
Потоковая передача тел ответов
По умолчанию Net::HTTP считывает весь ответ в память. Если вы обрабатываете большие файлы или хотите реализовать индикатор выполнения, можно вместо этого передавать тело ответа потоком непосредственно в IO.
Net::HTTP.start(hostname) do |http|
req = Net::HTTP::Get.new(uri)
http.request(req) do |res|
open('t.tmp', 'w') do |f|
res.read_body do |chunk|
f.write chunk
end
end
end
end
HTTPS
HTTPS включается для HTTP-соединения с помощью Net::HTTP#use_ssl=:
Net::HTTP.start(hostname, :use_ssl => true) do |http| req = Net::HTTP::Get.new(uri) res = http.request(req) end
Если же вам нужно просто выполнить GET-запрос, можно передать объект URI с URL HTTPS. Net::HTTP автоматически включает проверку TLS, если объект URI использует схему URI ‘https’:
uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com/> Net::HTTP.get(uri)
Прокси-сервер
Объект HTTP может использовать прокси-сервер.
Создать объект HTTP с прокси-сервером можно с помощью метода Net::HTTP.new или метода Net::HTTP.start.
Прокси можно задать аргументом p_addr или переменной окружения 'http_proxy'.
Использование прокси с аргументом p_addr в виде строки
Если аргумент p_addr — это строковое имя узла, возвращаемый объект http будет использовать указанный узел в качестве прокси:
http = Net::HTTP.new(hostname, nil, 'proxy.example') http.proxy? # => true http.proxy_from_env? # => false http.proxy_address # => "proxy.example" # These use default values. http.proxy_port # => 80 http.proxy_user # => nil http.proxy_pass # => nil
Также можно указать порт, имя пользователя и пароль прокси:
http = Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass') # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.proxy? # => true http.proxy_from_env? # => false http.proxy_address # => "proxy.example" http.proxy_port # => 8000 http.proxy_user # => "pname" http.proxy_pass # => "ppass"
Использование прокси через ‘ENV['http_proxy']’
Если переменной окружения 'http_proxy' присвоена строка URI, возвращаемый объект http будет использовать сервер, указанный в этом URI, в качестве прокси; обратите внимание, что строка URI должна содержать протокол, например 'http' или 'https':
ENV['http_proxy'] = 'http://example.com' http = Net::HTTP.new(hostname) http.proxy? # => true http.proxy_from_env? # => true http.proxy_address # => "example.com" # These use default values. http.proxy_port # => 80 http.proxy_user # => nil http.proxy_pass # => nil
Строка URI может содержать имя пользователя и пароль прокси, а также номер порта:
ENV['http_proxy'] = 'http://pname:ppass@example.com:8000' http = Net::HTTP.new(hostname) http.proxy? # => true http.proxy_from_env? # => true http.proxy_address # => "example.com" http.proxy_port # => 8000 http.proxy_user # => "pname" http.proxy_pass # => "ppass"
Фильтрация прокси
С помощью метода Net::HTTP.new (но не Net::HTTP.start) можно использовать аргумент p_no_proxy для фильтрации прокси:
-
Отклонить определённый адрес:
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example') http.proxy_address # => nil -
Отклонить определённые домены или поддомены:
http = Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example') http.proxy_address # => nil -
Отклонить определённые сочетания адресов и портов:
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234') http.proxy_address # => "proxy.example" http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000') http.proxy_address # => nil -
Отклонить список перечисленных выше типов, разделённых запятыми:
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000') http.proxy_address # => nil http = Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000') http.proxy_address # => nil
Сжатие и распаковка
Net::HTTP не сжимает тело запроса перед отправкой.
По умолчанию Net::HTTP добавляет заголовок 'Accept-Encoding' к новому объекту запроса:
Net::HTTP::Get.new(uri)['Accept-Encoding'] # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
Это указывает серверу выполнить zip-кодирование тела ответа, если оно есть; сервер не обязан это делать.
Net::HTTP не распаковывает тело ответа автоматически, если ответ содержит заголовок 'Content-Range'.
В противном случае распаковка (или её отсутствие) зависит от значения заголовка Content-Encoding:
-
'deflate','gzip'или'x-gzip': распаковывает тело и удаляет заголовок. -
'none'или'identity': не распаковывает тело, но удаляет заголовок. -
Любое другое значение: оставляет тело и заголовок без изменений.
Что здесь находится
Сначала рассмотрим, что находится в другом месте. Класс Net::HTTP:
-
Наследуется от класса Object.
Ниже приведён краткий обзор методов и атрибутов, сгруппированных по категориям.
Объекты Net::HTTP
Сеансы
-
::start: начинает новый сеанс в новом объекте Net::HTTP.
-
#started?: возвращает значение, указывающее, выполняется ли сеанс.
-
#finish: завершает активный сеанс.
-
#start: начинает новый сеанс в существующем объекте Net::HTTP (
self).
Соединения
-
:continue_timeout: возвращает время ожидания ответа continue.
-
#continue_timeout=: задаёт время ожидания ответа continue в секундах.
-
:keep_alive_timeout: возвращает время ожидания keep-alive.
-
:keep_alive_timeout=: задаёт время ожидания keep-alive.
-
:max_retries: возвращает максимальное количество повторных попыток.
-
#max_retries=: задаёт максимальное количество повторных попыток.
-
:open_timeout: возвращает время ожидания открытия соединения.
-
:open_timeout=: задаёт время ожидания открытия соединения.
-
:read_timeout: возвращает время ожидания открытия соединения.
-
:read_timeout=: задаёт время ожидания чтения.
-
:ssl_timeout: возвращает время ожидания SSL.
-
:ssl_timeout=: задаёт время ожидания SSL.
-
:write_timeout: возвращает время ожидания записи.
-
write_timeout=: задаёт время ожидания записи.
Запросы
-
::get: отправляет GET-запрос и возвращает строку тела ответа.
-
::get_print: отправляет GET-запрос и записывает строку тела ответа в $stdout.
-
::get_response: отправляет GET-запрос и возвращает объект ответа.
-
::post_form: отправляет POST-запрос с данными формы и возвращает объект ответа.
-
::post: отправляет POST-запрос с данными и возвращает объект ответа.
-
::put: отправляет PUT-запрос с данными и возвращает объект ответа.
-
#copy: отправляет COPY-запрос и возвращает объект ответа.
-
#delete: отправляет DELETE-запрос и возвращает объект ответа.
-
#get: отправляет GET-запрос и возвращает объект ответа.
-
#head: отправляет HEAD-запрос и возвращает объект ответа.
-
#lock: отправляет LOCK-запрос и возвращает объект ответа.
-
#mkcol: отправляет MKCOL-запрос и возвращает объект ответа.
-
#move: отправляет MOVE-запрос и возвращает объект ответа.
-
#options: отправляет OPTIONS-запрос и возвращает объект ответа.
-
#patch: отправляет PATCH-запрос и возвращает объект ответа.
-
#post: отправляет POST-запрос и возвращает объект ответа.
-
#propfind: отправляет PROPFIND-запрос и возвращает объект ответа.
-
#proppatch: отправляет PROPPATCH-запрос и возвращает объект ответа.
-
#put: отправляет PUT-запрос и возвращает объект ответа.
-
#request: отправляет запрос и возвращает объект ответа.
-
#request_get: отправляет GET-запрос и формирует объект ответа; если передан блок, вызывает его с этим объектом, иначе возвращает объект.
-
#request_head: отправляет HEAD-запрос и формирует объект ответа; если передан блок, вызывает его с этим объектом, иначе возвращает объект.
-
#request_post: отправляет POST-запрос и формирует объект ответа; если передан блок, вызывает его с этим объектом, иначе возвращает объект.
-
#send_request: отправляет запрос и возвращает объект ответа.
-
#trace: отправляет TRACE-запрос и возвращает объект ответа.
-
#unlock: отправляет UNLOCK-запрос и возвращает объект ответа.
Ответы
-
:close_on_empty_response: возвращает значение, указывающее, следует ли закрывать соединение при пустом ответе.
-
:close_on_empty_response=: задаёт, следует ли закрывать соединение при пустом ответе.
-
:ignore_eof: возвращает значение, указывающее, следует ли игнорировать конец файла при чтении тела ответа с заголовками
Content-Length. -
:ignore_eof=: задаёт, следует ли игнорировать конец файла при чтении тела ответа с заголовками
Content-Length. -
:response_body_encoding: возвращает кодировку, используемую для тела ответа.
-
#response_body_encoding=: задаёт кодировку тела ответа.
Прокси
-
:proxy_address: возвращает адрес прокси.
-
:proxy_address=: задаёт адрес прокси.
-
::proxy_class?: возвращает значение, указывающее, является ли
selfклассом прокси. -
#proxy?: возвращает значение, указывающее, использует ли
selfпрокси. -
#proxy_address: возвращает адрес прокси.
-
#proxy_from_env?: возвращает значение, указывающее, берётся ли прокси из переменной окружения.
-
:proxy_from_env=: задаёт, следует ли брать прокси из переменной окружения.
-
:proxy_pass: возвращает пароль прокси.
-
:proxy_pass=: задаёт пароль прокси.
-
:proxy_port: возвращает порт прокси.
-
:proxy_port=: задаёт порт прокси.
-
#proxy_user: возвращает имя пользователя прокси.
-
:proxy_user=: задаёт пользователя прокси.
Безопасность
-
:ca_file: возвращает путь к файлу сертификатов центра сертификации (CA).
-
:ca_file=: задаёт путь к файлу сертификатов центра сертификации (CA).
-
:ca_path: возвращает путь к каталогу CA, содержащему файлы сертификатов.
-
:ca_path=: задаёт путь к каталогу CA, содержащему файлы сертификатов.
-
:cert: возвращает объект
OpenSSL::X509::Certificate, используемый для аутентификации клиента. -
:cert=: задаёт объект
OpenSSL::X509::Certificate, используемый для аутентификации клиента. -
:cert_store: возвращает X509::Store, используемый для проверки сертификата узла.
-
:cert_store=: задаёт X509::Store, используемый для проверки сертификата узла.
-
:ciphers: возвращает доступные шифры SSL.
-
:ciphers=: задаёт доступные шифры SSL.
-
:extra_chain_cert: возвращает дополнительные сертификаты X509, которые будут добавлены в цепочку сертификатов.
-
:extra_chain_cert=: задаёт дополнительные сертификаты X509, которые будут добавлены в цепочку сертификатов.
-
:key: возвращает объект
OpenSSL::PKey::RSAилиOpenSSL::PKey::DSA. -
:key=: задаёт объект
OpenSSL::PKey::RSAилиOpenSSL::PKey::DSA. -
:max_version: возвращает максимальную версию SSL.
-
:max_version=: задаёт максимальную версию SSL.
-
:min_version: возвращает минимальную версию SSL.
-
:min_version=: задаёт минимальную версию SSL.
-
#peer_cert: возвращает цепочку сертификатов X509 для узла, являющегося другой стороной сокета сеанса.
-
:ssl_version: возвращает версию SSL.
-
:ssl_version=: задаёт версию SSL.
-
#use_ssl=: задаёт, следует ли использовать протокол TLS для нового сеанса.
-
#use_ssl?: возвращает значение, указывающее, использует ли
selfSSL. -
:verify_callback: возвращает функцию обратного вызова для проверки сертификата сервера.
-
:verify_callback=: задаёт функцию обратного вызова для проверки сертификата сервера.
-
:verify_depth: возвращает максимальную глубину проверки цепочки сертификатов.
-
:verify_depth=: задаёт максимальную глубину проверки цепочки сертификатов.
-
:verify_hostname: возвращает флаги проверки сертификата сервера в начале сеанса SSL/TLS.
-
:verify_hostname=: задаёт флаги проверки сертификата сервера в начале сеанса SSL/TLS.
-
:verify_mode: возвращает флаги проверки сертификата сервера в начале сеанса SSL/TLS.
-
:verify_mode=: задаёт флаги проверки сертификата сервера в начале сеанса SSL/TLS.
Адреса и порты
-
:address: возвращает строковое имя узла или IP-адрес узла.
-
::default_port: возвращает целое число 80 — порт по умолчанию для запросов
HTTP. -
::http_default_port: возвращает целое число 80 — порт по умолчанию для запросов
HTTP. -
::https_default_port: возвращает целое число 443 — порт по умолчанию для запросов HTTPS.
-
#ipaddr: возвращает IP-адрес для соединения.
-
#ipaddr=: задаёт IP-адрес для соединения.
-
:local_host: возвращает строковое имя локального узла, используемое для установки соединения.
-
:local_host=: задаёт строковое имя локального узла, используемое для установки соединения.
-
:local_port: возвращает целое число — локальный порт, используемый для установки соединения.
-
:local_port=: задаёт целое число — локальный порт, используемый для установки соединения.
-
:port: возвращает целое число — номер порта.
Версия HTTP
-
::version_1_2? (имеет псевдоним ::version_1_2): возвращает true; сохранён для совместимости.
Отладка
-
#set_debug_output: задаёт поток вывода для отладки.
Атрибуты
Позволяет задать конфигурацию по умолчанию, которая будет использоваться при создании нового соединения.
Пример:
Net::HTTP.default_configuration = {
read_timeout: 1,
write_timeout: 1
}
http = Net::HTTP.new(hostname)
http.open_timeout # => 60
http.read_timeout # => 1
http.write_timeout # => 1
Возвращает адрес прокси-сервера или nil, если он не задан; см. Прокси-сервер в Net::HTTP.
Возвращает пароль для доступа к прокси-серверу или nil, если он не задан; см. Прокси-сервер в Net::HTTP.
Возвращает номер порта прокси-сервера или nil, если он не задан; см. Прокси-сервер в Net::HTTP.
Использовать SSL при взаимодействии с прокси-сервером. Если Net::HTTP не использует прокси-сервер, возвращает nil.
Возвращает имя пользователя для доступа к прокси-серверу или nil, если оно не задано; см. Прокси-сервер в Net::HTTP.
Возвращает строковое имя хоста или IP-адрес хоста, переданный в качестве аргумента address в ::new.
Задаёт или возвращает путь к файлу сертификата CA в формате PEM.
Задаёт или возвращает путь к каталогу CA, содержащему файлы сертификатов в формате PEM.
Задаёт или возвращает объект OpenSSL::X509::Certificate, используемый для аутентификации клиента.
Задаёт или возвращает X509::Store, используемый для проверки сертификата узла.
Задаёт или возвращает доступные шифры SSL. См. :SSL::SSLContext#ciphers=.
Задаёт или возвращает, следует ли закрывать соединение, если ответ пуст; исходное значение — false.
Возвращает значение тайм-аута ожидания продолжения; см. continue_timeout=.
Задаёт или возвращает дополнительные сертификаты X509, добавляемые в цепочку сертификатов. См. :SSL::SSLContext#add_certificate.
Задаёт или возвращает, следует ли игнорировать конец файла при чтении тела ответа с заголовками Content-Length; исходное значение — true.
Задаёт или возвращает числовое значение (Integer или Float) — количество секунд, в течение которых соединение остаётся открытым после отправки запроса; исходное значение — 2. Если в течение указанного интервала поступает новый запрос, используется всё ещё открытое соединение; в противном случае соединение уже будет закрыто и будет открыто новое.
Задаёт или возвращает объект OpenSSL::PKey::RSA или OpenSSL::PKey::DSA.
Задаёт или возвращает строковое имя локального хоста, используемого для установки соединения; исходное значение — nil.
Задаёт или возвращает целочисленный номер локального порта, используемого для установки соединения; исходное значение — nil.
Возвращает максимальное число повторных попыток для идемпотентного запроса; см. max_retries=.
Задаёт или возвращает максимальную версию SSL. См. :SSL::SSLContext#max_version=.
Задаёт или возвращает минимальную версию SSL. См. :SSL::SSLContext#min_version=.
Задаёт или возвращает числовое значение (Integer или Float) — количество секунд ожидания установления соединения; исходное значение — 60. Если соединение не будет установлено в течение указанного интервала, возникнет исключение.
Задаёт адрес прокси-сервера; см. Прокси-сервер.
Задаёт, следует ли определять прокси-сервер из переменной окружения «ENV['http_proxy']»; см. Использование прокси-сервера через ENV[‘http_proxy’].
Задаёт пароль прокси-сервера; см. Прокси-сервер.
Задаёт порт прокси-сервера; см. Прокси-сервер.
Задаёт имя пользователя прокси-сервера; см. Прокси-сервер.
Возвращает числовое значение (Integer или Float) — количество секунд ожидания чтения одного блока (за один вызов read(2)); см. read_timeout=.
Возвращает кодировку, используемую для тела ответа; см. response_body_encoding=.
Задаёт или возвращает тайм-аут SSL в секундах.
Задаёт или возвращает версию SSL. См. :SSL::SSLContext#ssl_version=.
Задаёт или возвращает функцию обратного вызова для проверки сертификата сервера.
Задаёт или возвращает максимальную глубину проверки цепочки сертификатов.
Задаёт или возвращает, следует ли проверять действительность сертификата сервера для имени хоста. См. :SSL::SSLContext#verify_hostname=.
Задаёт или возвращает флаги проверки сертификата сервера в начале сеанса SSL/TLS. Допустимы OpenSSL::SSL::VERIFY_NONE и OpenSSL::SSL::VERIFY_PEER.
Возвращает числовое значение (Integer или Float) — количество секунд ожидания записи одного блока (за один вызов write(2)); см. write_timeout=.
Открытые методы класса
# File lib/net/http.rb, line 935 def HTTP.default_port http_default_port() end
Возвращает целое число 80 — порт по умолчанию для HTTP-запросов:
Net::HTTP.default_port # => 80
# File lib/net/http.rb, line 804 def HTTP.get(uri_or_host, path_or_headers = nil, port = nil) get_response(uri_or_host, path_or_headers, port).body end
Отправляет GET-запрос и возвращает тело HTTP-ответа в виде строки.
При строковых аргументах hostname и path:
hostname = 'jsonplaceholder.typicode.com' path = '/todos/1' puts Net::HTTP.get(hostname, path)
Вывод:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
С объектом URI uri и необязательным аргументом-хешем headers:
uri = URI('https://jsonplaceholder.typicode.com/todos/1')
headers = {'Content-type' => 'application/json; charset=UTF-8'}
Net::HTTP.get(uri, headers)
См. также:
-
Net::HTTP::Get: класс запроса для HTTP-методаGET. -
Net::HTTP#get: вспомогательный метод для HTTP-методаGET.
# File lib/net/http.rb, line 763
def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
get_response(uri_or_host, path_or_headers, port) {|res|
res.read_body do |chunk|
$stdout.print chunk
end
}
nil
end Как Net::HTTP.get, но записывает возвращённое тело в $stdout; возвращает nil.
# File lib/net/http.rb, line 814
def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
if path_or_headers && !path_or_headers.is_a?(Hash)
host = uri_or_host
path = path_or_headers
new(host, port || HTTP.default_port).start {|http|
return http.request_get(path, &block)
}
else
uri = uri_or_host
headers = path_or_headers
start(uri.hostname, uri.port,
:use_ssl => uri.scheme == 'https') {|http|
return http.request_get(uri, headers, &block)
}
end
end Как Net::HTTP.get, но возвращает объект Net::HTTPResponse вместо строки тела.
# File lib/net/http.rb, line 943 def HTTP.http_default_port 80 end
Возвращает целое число 80 — порт по умолчанию для HTTP-запросов:
Net::HTTP.http_default_port # => 80
# File lib/net/http.rb, line 951 def HTTP.https_default_port 443 end
Возвращает целое число 443 — порт по умолчанию для HTTPS-запросов:
Net::HTTP.https_default_port # => 443
# File lib/net/http.rb, line 1100
def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil, p_use_ssl = nil)
http = super address, port
if proxy_class? then # from Net::HTTP::Proxy()
http.proxy_from_env = @proxy_from_env
http.proxy_address = @proxy_address
http.proxy_port = @proxy_port
http.proxy_user = @proxy_user
http.proxy_pass = @proxy_pass
http.proxy_use_ssl = @proxy_use_ssl
elsif p_addr == :ENV then
http.proxy_from_env = true
else
if p_addr && p_no_proxy && !URI::Generic.use_proxy?(address, address, port, p_no_proxy)
p_addr = nil
p_port = nil
end
http.proxy_address = p_addr
http.proxy_port = p_port || default_port
http.proxy_user = p_user
http.proxy_pass = p_pass
http.proxy_use_ssl = p_use_ssl
end
http
end Возвращает новый объект Net::HTTP http (но не открывает TCP-соединение или HTTP-сеанс).
Если указан только строковый аргумент address (а ENV['http_proxy'] не задан или равен nil), возвращаемый http:
-
Имеет указанный адрес.
-
Имеет номер порта по умолчанию —
Net::HTTP.default_port(80). -
Не использует прокси.
Пример:
http = Net::HTTP.new(hostname) # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.address # => "jsonplaceholder.typicode.com" http.port # => 80 http.proxy? # => false
Если также указан целочисленный аргумент port, возвращаемый http имеет указанный порт:
http = Net::HTTP.new(hostname, 8000) # => #<Net::HTTP jsonplaceholder.typicode.com:8000 open=false> http.port # => 8000
Сведения об аргументах p_addr–p_no_proxy, задающих прокси, см. в разделе Прокси-сервер.
# File lib/net/http.rb, line 857
def HTTP.post(url, data, header = nil)
start(url.hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.post(url, data, header)
}
end Отправляет данные на хост; возвращает объект Net::HTTPResponse.
Аргумент url должен быть URL-адресом; аргумент data должен быть строкой:
_uri = uri.dup
_uri.path = '/posts'
data = '{"title": "foo", "body": "bar", "userId": 1}'
headers = {'content-type': 'application/json'}
res = Net::HTTP.post(_uri, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true>
puts res.body
Вывод:
{
"title": "foo",
"body": "bar",
"userId": 1,
"id": 101
}
См. также:
-
Net::HTTP::Post: класс запроса для HTTP-методаPOST. -
Net::HTTP#post: вспомогательный метод для HTTP-методаPOST.
# File lib/net/http.rb, line 884
def HTTP.post_form(url, params)
req = Post.new(url)
req.form_data = params
req.basic_auth url.user, url.password if url.user
start(url.hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.request(req)
}
end Отправляет данные на хост; возвращает объект Net::HTTPResponse.
Аргумент url должен быть объектом URI; аргумент data должен быть хешем:
_uri = uri.dup
_uri.path = '/posts'
data = {title: 'foo', body: 'bar', userId: 1}
res = Net::HTTP.post_form(_uri, data) # => #<Net::HTTPCreated 201 Created readbody=true>
puts res.body
Вывод:
{
"title": "foo",
"body": "bar",
"userId": "1",
"id": 101
}
# File lib/net/http.rb, line 1826 def proxy_class? defined?(@is_proxy_class) ? @is_proxy_class : false end
Возвращает true, если self — класс, созданный HTTP::Proxy.
# File lib/net/http.rb, line 920
def HTTP.put(url, data, header = nil)
start(url.hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.put(url, data, header)
}
end Отправляет PUT-запрос серверу; возвращает объект Net::HTTPResponse.
Аргумент url должен быть URL-адресом; аргумент data должен быть строкой:
_uri = uri.dup
_uri.path = '/posts'
data = '{"title": "foo", "body": "bar", "userId": 1}'
headers = {'content-type': 'application/json'}
res = Net::HTTP.put(_uri, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true>
puts res.body
Вывод:
{
"title": "foo",
"body": "bar",
"userId": 1,
"id": 101
}
См. также:
-
Net::HTTP::Put: класс запроса для HTTP-методаPUT. -
Net::HTTP#put: вспомогательный метод для HTTP-методаPUT.
# File lib/net/http.rb, line 1045
def HTTP.start(address, *arg, &block) # :yield: +http+
arg.pop if opt = Hash.try_convert(arg[-1])
port, p_addr, p_port, p_user, p_pass = *arg
p_addr = :ENV if arg.size < 2
port = https_default_port if !port && opt && opt[:use_ssl]
http = new(address, port, p_addr, p_port, p_user, p_pass)
http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr]
if opt
if opt[:use_ssl]
opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
end
http.methods.grep(/\A(\w+)=\z/) do |meth|
key = $1.to_sym
opt.key?(key) or next
http.__send__(meth, opt[key])
end
end
http.start(&block)
end Создаёт новый объект Net::HTTP http с помощью Net::HTTP.new:
-
Сведения об аргументах
addressиportсм. в описанииNet::HTTP.new. -
Сведения об аргументах
p_addr–p_pass, задающих прокси, см. в разделе Прокси-сервер. -
Сведения об аргументе
optsсм. ниже.
Если блок не задан:
-
Вызывает
http.startбез блока (см.start), который открывает TCP-соединение и HTTP-сеанс. -
Возвращает
http. -
Вызывающая сторона должна вызвать
finish, чтобы закрыть сеанс:http = Net::HTTP.start(hostname) http.started? # => true http.finish http.started? # => false
Если блок задан:
-
Вызывает
http.startс блоком (см.start), который:-
Открывает TCP-соединение и HTTP-сеанс.
-
Вызывает блок, в котором может быть выполнено любое количество запросов к хосту.
-
Закрывает HTTP-сеанс и TCP-соединение при выходе из блока.
-
Возвращает значение блока
object.
-
-
Возвращает
object.
Пример:
hostname = 'jsonplaceholder.typicode.com'
Net::HTTP.start(hostname) do |http|
puts http.get('/todos/1').body
puts http.get('/todos/2').body
end
Вывод:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
{
"userId": 1,
"id": 2,
"title": "quis ut nam facilis et officia qui",
"completed": false
}
Если последний переданный аргумент — хеш, он является хешем opts, где каждый ключ — это метод или метод доступа для вызова, а соответствующее значение — значение, которое ему будет присвоено.
Ключи могут включать:
Примечание: если port равно nil, а opts[:use_ssl] — истинное значение, в new передаётся Net::HTTP.https_default_port, а не port.
# File lib/net/http.rb, line 738 def HTTP.version_1_2 true end
Возвращает true; метод сохранён для обеспечения совместимости.
# File lib/net/http.rb, line 743 def HTTP.version_1_2? true end
Возвращает true; метод сохранён для обеспечения совместимости.
Публичные методы экземпляра
# File lib/net/http.rb, line 1451 def continue_timeout=(sec) @socket.continue_timeout = sec if @socket @continue_timeout = sec end
Задаёт значение тайм-аута ожидания продолжения — количество секунд ожидания ожидаемого ответа 100 Continue. Если объект HTTP не получает ответ в течение этого времени, он отправляет тело запроса.
# File lib/net/http.rb, line 2195 def copy(path, initheader = nil) request(Copy.new(path, initheader)) end
Отправляет серверу запрос COPY; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Copy, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.copy('/todos/1')
# File lib/net/http.rb, line 2169
def delete(path, initheader = {'Depth' => 'Infinity'})
request(Delete.new(path, initheader))
end Отправляет серверу запрос DELETE; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Delete, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.delete('/todos/1')
# File lib/net/http.rb, line 1770 def finish raise IOError, 'HTTP session not yet started' unless started? do_finish end
Завершает сеанс HTTP:
http = Net::HTTP.new(hostname) http.start http.started? # => true http.finish # => nil http.started? # => false
Вызывает IOError, если сеанс не активен.
# File lib/net/http.rb, line 1981
def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
res = nil
request(Get.new(path, initheader)) {|r|
r.read_body dest, &block
res = r
}
res
end Отправляет серверу запрос GET; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Get, созданном из строки path и хеша начальных заголовков initheader.
Если передан блок, вызывает его с телом ответа:
http = Net::HTTP.new(hostname)
http.get('/todos/1') do |res|
p res
end # => #<Net::HTTPOK 200 OK readbody=true>
Вывод:
"{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
Если блок не передан, просто возвращает объект ответа:
http.get('/') # => #<Net::HTTPOK 200 OK readbody=true>
См. также:
-
Net::HTTP::Get: класс запроса для метода HTTP GET. -
Net::HTTP.get: отправляет запрос GET и возвращает тело ответа.
# File lib/net/http.rb, line 2005 def head(path, initheader = nil) request(Head.new(path, initheader)) end
Отправляет серверу запрос HEAD; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Head, созданном из строки path и хеша начальных заголовков initheader:
res = http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
res.body # => nil
res.to_hash.take(3)
# =>
[["date", ["Wed, 15 Feb 2023 15:25:42 GMT"]],
["content-type", ["application/json; charset=utf-8"]],
["connection", ["close"]]]
# File lib/net/http.rb, line 1205
def inspect
"#<#{self.class} #{@address}:#{@port} open=#{started?}>"
end Возвращает строковое представление self:
Net::HTTP.new(hostname).inspect # => "#<Net::HTTP jsonplaceholder.typicode.com:80 open=false>"
# File lib/net/http.rb, line 1345 def ipaddr started? ? @socket.io.peeraddr[3] : @ipaddr end
Возвращает IP-адрес соединения.
Если сеанс не был начат, возвращает значение, заданное методом ipaddr=, или nil, если значение не задано:
http = Net::HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = '172.67.155.76' http.ipaddr # => "172.67.155.76"
Если сеанс был начат, возвращает IP-адрес сокета:
http = Net::HTTP.new(hostname) http.start http.ipaddr # => "172.67.155.76" http.finish
# File lib/net/http.rb, line 1357 def ipaddr=(addr) raise IOError, "ipaddr value changed, but session already started" if started? @ipaddr = addr end
Задаёт IP-адрес соединения:
http = Net::HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = '172.67.155.76' http.ipaddr # => "172.67.155.76"
IP-адрес нельзя задать, если сеанс уже начат.
# File lib/net/http.rb, line 2115 def lock(path, body, initheader = nil) request(Lock.new(path, initheader), body) end
Отправляет серверу запрос LOCK; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Lock, созданном из строки path, строки body и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.lock('/todos/1', data)
# File lib/net/http.rb, line 1391
def max_retries=(retries)
retries = retries.to_int
if retries < 0
raise ArgumentError, 'max_retries should be non-negative integer number'
end
@max_retries = retries
end Задаёт максимальное количество повторных попыток для идемпотентного запроса при возникновении Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError, Timeout::Error. Начальное значение — 1.
Аргумент retries должен быть неотрицательным числовым значением:
http = Net::HTTP.new(hostname) http.max_retries = 2 # => 2 http.max_retries # => 2
# File lib/net/http.rb, line 2209 def mkcol(path, body = nil, initheader = nil) request(Mkcol.new(path, initheader), body) end
Отправляет серверу запрос MKCOL; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Mkcol, созданном из строки path, строки body и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http.mkcol('/todos/1', data)
http = Net::HTTP.new(hostname)
# File lib/net/http.rb, line 2182 def move(path, initheader = nil) request(Move.new(path, initheader)) end
Отправляет серверу запрос MOVE; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Move, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.move('/todos/1')
# File lib/net/http.rb, line 2142 def options(path, initheader = nil) request(Options.new(path, initheader)) end
Отправляет серверу запрос Options; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Options, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.options('/')
# File lib/net/http.rb, line 2068 def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ send_entity(path, data, initheader, dest, Patch, &block) end
Отправляет серверу запрос PATCH; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Patch, созданном из строки path, строки data и хеша начальных заголовков initheader.
Если передан блок, вызывает его с телом ответа:
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.patch('/todos/1', data) do |res|
p res
end # => #<Net::HTTPOK 200 OK readbody=true>
Вывод:
"{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false,\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\"\n}"
Если блок не передан, просто возвращает объект ответа:
http.patch('/todos/1', data) # => #<Net::HTTPCreated 201 Created readbody=true>
# File lib/net/http.rb, line 1593
def peer_cert
if not use_ssl? or not @socket
return nil
end
@socket.io.peer_cert
end Возвращает цепочку сертификатов X509 (массив строк) для однорангового узла сокета сеанса или nil, если сертификаты отсутствуют.
# File lib/net/http.rb, line 2039 def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ send_entity(path, data, initheader, dest, Post, &block) end
Отправляет серверу запрос POST; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Post, созданном из строки path, строки data и хеша начальных заголовков initheader.
Если передан блок, вызывает его с телом ответа:
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.post('/todos', data) do |res|
p res
end # => #<Net::HTTPCreated 201 Created readbody=true>
Вывод:
"{\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\",\n \"id\": 201\n}"
Если блок не передан, просто возвращает объект ответа:
http.post('/todos', data) # => #<Net::HTTPCreated 201 Created readbody=true>
См. также:
-
Net::HTTP::Post: класс запроса для метода HTTP POST. -
Net::HTTP.post: отправляет запрос POST и возвращает тело ответа.
# File lib/net/http.rb, line 2156
def propfind(path, body = nil, initheader = {'Depth' => '0'})
request(Propfind.new(path, initheader), body)
end Отправляет серверу запрос PROPFIND; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Propfind, созданном из строки path, строки body и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.propfind('/todos/1', data)
# File lib/net/http.rb, line 2101 def proppatch(path, body, initheader = nil) request(Proppatch.new(path, initheader), body) end
Отправляет серверу запрос PROPPATCH; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Proppatch, созданном из строки path, строки body и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.proppatch('/todos/1', data)
# File lib/net/http.rb, line 1852 def proxy? !!(@proxy_from_env ? proxy_uri : @proxy_address) end
Возвращает true, если задан прокси-сервер, и false в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 1874
def proxy_address
if @proxy_from_env then
proxy_uri&.hostname
else
@proxy_address
end
end Возвращает адрес прокси-сервера, если он задан, и nil в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 1859 def proxy_from_env? @proxy_from_env end
Возвращает true, если прокси-сервер задан в окружении, и false в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 1905
def proxy_pass
if @proxy_from_env
pass = proxy_uri&.password
unescape(pass) if pass
else
@proxy_pass
end
end Возвращает пароль прокси-сервера, если он задан, и nil в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 1884
def proxy_port
if @proxy_from_env then
proxy_uri&.port
else
@proxy_port
end
end Возвращает номер порта прокси-сервера, если он задан, и nil в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 1894
def proxy_user
if @proxy_from_env
user = proxy_uri&.user
unescape(user) if user
else
@proxy_user
end
end Возвращает имя пользователя прокси-сервера, если оно задано, и nil в противном случае; см. Прокси-сервер.
# File lib/net/http.rb, line 2087 def put(path, data, initheader = nil) request(Put.new(path, initheader), data) end
Отправляет серверу запрос PUT; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Put, созданном из строки path, строки data и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.put('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
См. также:
-
Net::HTTP::Put: класс запроса для метода HTTP PUT. -
Net::HTTP.put: отправляет запрос PUT и возвращает тело ответа.
# File lib/net/http.rb, line 1414 def read_timeout=(sec) @socket.read_timeout = sec if @socket @read_timeout = sec end
Задаёт время ожидания чтения в секундах для self как целое число sec; начальное значение — 60.
Аргумент sec должен быть неотрицательным числовым значением:
http = Net::HTTP.new(hostname)
http.read_timeout # => 60
http.get('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
http.read_timeout = 0
http.get('/todos/1') # Raises Net::ReadTimeout.
# File lib/net/http.rb, line 2367
def request(req, body = nil, &block) # :yield: +response+
unless started?
start {
req['connection'] ||= 'close'
return request(req, body, &block)
}
end
if proxy_user()
req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
end
req.set_body_internal body
res = transport_request(req, &block)
if sspi_auth?(res)
sspi_auth(req)
res = transport_request(req, &block)
end
res
end Отправляет серверу заданный запрос req; формирует ответ в виде объекта Net::HTTPResponse.
Заданный req должен быть экземпляром подкласса Net::HTTPRequest. Аргумент body следует указывать только в том случае, если он необходим для запроса.
Если блок не передан, возвращает объект ответа:
http = Net::HTTP.new(hostname)
req = Net::HTTP::Get.new('/todos/1')
http.request(req)
# => #<Net::HTTPOK 200 OK readbody=true>
req = Net::HTTP::Post.new('/todos')
http.request(req, 'xyzzy')
# => #<Net::HTTPCreated 201 Created readbody=true>
Если передан блок, вызывает его с объектом ответа и возвращает ответ:
req = Net::HTTP::Get.new('/todos/1')
http.request(req) do |res|
p res
end # => #<Net::HTTPOK 200 OK readbody=true>
Вывод:
#<Net::HTTPOK 200 OK readbody=false>
# File lib/net/http.rb, line 2248 def request_get(path, initheader = nil, &block) # :yield: +response+ request(Get.new(path, initheader), &block) end
Отправляет серверу запрос GET; формирует ответ в виде объекта Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Get, созданном из строки path и хеша начальных заголовков initheader.
Если блок не передан, возвращает объект ответа:
http = Net::HTTP.new(hostname)
http.request_get('/todos') # => #<Net::HTTPOK 200 OK readbody=true>
Если передан блок, вызывает его с объектом ответа и возвращает объект ответа:
http.request_get('/todos') do |res|
p res
end # => #<Net::HTTPOK 200 OK readbody=true>
Вывод:
#<Net::HTTPOK 200 OK readbody=false>
# File lib/net/http.rb, line 2261 def request_head(path, initheader = nil, &block) request(Head.new(path, initheader), &block) end
Отправляет серверу запрос HEAD; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Head, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
# File lib/net/http.rb, line 2288 def request_post(path, data, initheader = nil, &block) # :yield: +response+ request Post.new(path, initheader), data, &block end
Отправляет серверу запрос POST; формирует ответ в виде объекта Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Post, созданном из строки path, строки data и хеша начальных заголовков initheader.
Если блок не передан, возвращает объект ответа:
http = Net::HTTP.new(hostname)
http.post('/todos', 'xyzzy')
# => #<Net::HTTPCreated 201 Created readbody=true>
Если передан блок, вызывает его с телом ответа и возвращает объект ответа:
http.post('/todos', 'xyzzy') do |res|
p res
end # => #<Net::HTTPCreated 201 Created readbody=true>
Вывод:
"{\n \"xyzzy\": \"\",\n \"id\": 201\n}"
# File lib/net/http.rb, line 1299 def response_body_encoding=(value) value = Encoding.find(value) if value.is_a?(String) @response_body_encoding = value end
Задаёт кодировку тела ответа; возвращает кодировку.
Заданное значение value может быть:
-
Объектом
Encoding. -
Название кодировки.
-
Псевдоним названия кодировки.
См. Encoding.
Примеры:
http = Net::HTTP.new(hostname) http.response_body_encoding = Encoding::US_ASCII # => #<Encoding:US-ASCII> http.response_body_encoding = 'US-ASCII' # => "US-ASCII" http.response_body_encoding = 'ASCII' # => "ASCII"
# File lib/net/http.rb, line 2331 def send_request(name, path, data = nil, header = nil) has_response_body = name != 'HEAD' r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header) request r, data end
Отправляет серверу HTTP-запрос; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTPRequest, созданном из строки path, строки data и хеша начальных заголовков header. Этот объект является экземпляром подкласса Net::HTTPRequest, соответствующего заданной строке name в верхнем регистре. Она должна быть методом HTTP-запроса или методом запроса WebDAV.
Примеры:
http = Net::HTTP.new(hostname)
http.send_request('GET', '/todos/1')
# => #<Net::HTTPOK 200 OK readbody=true>
http.send_request('POST', '/todos', 'xyzzy')
# => #<Net::HTTPCreated 201 Created readbody=true>
# File lib/net/http.rb, line 1258 def set_debug_output(output) warn 'Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started? @debug_output = output end
ПРЕДУПРЕЖДЕНИЕ Этот метод создаёт серьёзную уязвимость. Никогда не используйте его в производственном коде.
Задаёт поток вывода для отладки:
http = Net::HTTP.new(hostname)
File.open('t.tmp', 'w') do |file|
http.set_debug_output(file)
http.start
http.get('/nosuch/1')
http.finish
end
puts File.read('t.tmp')
Вывод:
opening connection to jsonplaceholder.typicode.com:80...
opened
<- "GET /nosuch/1 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: jsonplaceholder.typicode.com\r\n\r\n"
-> "HTTP/1.1 404 Not Found\r\n"
-> "Date: Mon, 12 Dec 2022 21:14:11 GMT\r\n"
-> "Content-Type: application/json; charset=utf-8\r\n"
-> "Content-Length: 2\r\n"
-> "Connection: keep-alive\r\n"
-> "X-Powered-By: Express\r\n"
-> "X-Ratelimit-Limit: 1000\r\n"
-> "X-Ratelimit-Remaining: 999\r\n"
-> "X-Ratelimit-Reset: 1670879660\r\n"
-> "Vary: Origin, Accept-Encoding\r\n"
-> "Access-Control-Allow-Credentials: true\r\n"
-> "Cache-Control: max-age=43200\r\n"
-> "Pragma: no-cache\r\n"
-> "Expires: -1\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "Etag: W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"\r\n"
-> "Via: 1.1 vegur\r\n"
-> "CF-Cache-Status: MISS\r\n"
-> "Server-Timing: cf-q-config;dur=1.3000000762986e-05\r\n"
-> "Report-To: {\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yOr40jo%2BwS1KHzhTlVpl54beJ5Wx2FcG4gGV0XVrh3X9OlR5q4drUn2dkt5DGO4GDcE%2BVXT7CNgJvGs%2BZleIyMu8CLieFiDIvOviOY3EhHg94m0ZNZgrEdpKD0S85S507l1vsEwEHkoTm%2Ff19SiO\"}],\"group\":\"cf-nel\",\"max_age\":604800}\r\n"
-> "NEL: {\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}\r\n"
-> "Server: cloudflare\r\n"
-> "CF-RAY: 778977dc484ce591-DFW\r\n"
-> "alt-svc: h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400\r\n"
-> "\r\n"
reading 2 bytes...
-> "{}"
read 2 bytes
Conn keep-alive # File lib/net/http.rb, line 1621
def start # :yield: http
raise IOError, 'HTTP session already opened' if @started
if block_given?
begin
do_start
return yield(self)
ensure
do_finish
end
end
do_start
self
end Начинает сеанс HTTP.
Если блок не передан, возвращает self:
http = Net::HTTP.new(hostname) # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.start # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=true> http.started? # => true http.finish
Если блок передан, вызывает его с self, завершает сеанс после выхода из блока и возвращает значение блока:
http.start do |http| http end # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.started? # => false
# File lib/net/http.rb, line 1484 def started? @started end
Возвращает true, если сеанс HTTP был начат:
http = Net::HTTP.new(hostname) http.started? # => false http.start http.started? # => true http.finish # => nil http.started? # => false Net::HTTP.start(hostname) do |http| http.started? end # => true http.started? # => false
# File lib/net/http.rb, line 2222 def trace(path, initheader = nil) request(Trace.new(path, initheader)) end
Отправляет серверу запрос TRACE; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос основан на объекте Net::HTTP::Trace, созданном из строки path и хеша начальных заголовков initheader.
http = Net::HTTP.new(hostname)
http.trace('/todos/1')
# File lib/net/http.rb, line 2129 def unlock(path, body, initheader = nil) request(Unlock.new(path, initheader), body) end
Отправляет серверу запрос UNLOCK; возвращает экземпляр подкласса Net::HTTPResponse.
Запрос формируется на основе объекта Net::HTTP::Unlock, созданного из строки path, строки body и хеша начальных заголовков initheader.
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
http = Net::HTTP.new(hostname)
http.unlock('/todos/1', data)
# File lib/net/http.rb, line 1506
def use_ssl=(flag)
flag = flag ? true : false
if started? and @use_ssl != flag
raise IOError, "use_ssl value changed, but session already started"
end
@use_ssl = flag
end Задаёт, будет ли новый сеанс использовать протокол защиты транспортного уровня:
Вызывает исключение IOError при попытке изменить значение во время сеанса.
Вызывает исключение OpenSSL::SSL::SSLError, если порт не является портом HTTPS.
# File lib/net/http.rb, line 1496 def use_ssl? @use_ssl end
Возвращает true, если self использует SSL, и false в противном случае. См. Net::HTTP#use_ssl=.
# File lib/net/http.rb, line 1438 def write_timeout=(sec) @socket.write_timeout = sec if @socket @write_timeout = sec end
Задаёт время ожидания записи в секундах для self, равное целому числу sec; начальное значение — 60.
Аргумент sec должен быть неотрицательным числовым значением:
_uri = uri.dup
_uri.path = '/posts'
body = 'bar' * 200000
data = <<EOF
{"title": "foo", "body": "#{body}", "userId": "1"}
EOF
headers = {'content-type': 'application/json'}
http = Net::HTTP.new(hostname)
http.write_timeout # => 60
http.post(_uri.path, data, headers)
# => #<Net::HTTPCreated 201 Created readbody=true>
http.write_timeout = 0
http.post(_uri.path, data, headers) # Raises Net::WriteTimeout.
Приватные методы экземпляра
# File lib/net/http.rb, line 2539
def addr_port
addr = address
addr = "[#{addr}]" if addr.include?(":")
default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port
default_port == port ? addr : "#{addr}:#{port}"
end утилиты
# File lib/net/http.rb, line 2456
def begin_transport(req)
if @socket.closed?
connect
elsif @last_communicated
if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
debug 'Conn close because of keep_alive_timeout'
@socket.close
connect
elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
debug "Conn close because of EOF"
@socket.close
connect
end
end
if not req.response_body_permitted? and @close_on_empty_response
req['connection'] ||= 'close'
end
req.update_uri address, port, use_ssl?
req['host'] ||= addr_port()
end # File lib/net/http.rb, line 1641
def connect
if use_ssl?
# reference early to load OpenSSL before connecting,
# as OpenSSL may take time to load.
@ssl_context = OpenSSL::SSL::SSLContext.new
end
if proxy? then
conn_addr = proxy_address
conn_port = proxy_port
else
conn_addr = conn_address
conn_port = port
end
debug "opening connection to #{conn_addr}:#{conn_port}..."
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
begin
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
rescue => e
raise e, "Failed to open TCP connection to " +
"#{conn_addr}:#{conn_port} (#{e.message})"
end
}
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
debug "opened"
if use_ssl?
if proxy?
if @proxy_use_ssl
proxy_sock = OpenSSL::SSL::SSLSocket.new(s)
ssl_socket_connect(proxy_sock, @open_timeout)
else
proxy_sock = s
end
proxy_sock = BufferedIO.new(proxy_sock, read_timeout: @read_timeout,
write_timeout: @write_timeout,
continue_timeout: @continue_timeout,
debug_output: @debug_output)
buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \
"Host: #{@address}:#{@port}\r\n"
if proxy_user
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
buf << "Proxy-Authorization: Basic #{credential}\r\n"
end
buf << "\r\n"
proxy_sock.write(buf)
HTTPResponse.read_new(proxy_sock).value
# assuming nothing left in buffers after successful CONNECT response
end
ssl_parameters = Hash.new
iv_list = instance_variables
SSL_IVNAMES.each_with_index do |ivname, i|
if iv_list.include?(ivname)
value = instance_variable_get(ivname)
unless value.nil?
ssl_parameters[SSL_ATTRIBUTES[i]] = value
end
end
end
@ssl_context.set_params(ssl_parameters)
unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
@ssl_context.session_cache_mode =
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
end
if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
end
# Still do the post_connection_check below even if connecting
# to IP address
verify_hostname = @ssl_context.verify_hostname
# Server Name Indication (SNI) RFC 3546/6066
case @address
when Resolv::IPv4::Regex, Resolv::IPv6::Regex
# don't set SNI, as IP addresses in SNI is not valid
# per RFC 6066, section 3.
# Avoid openssl warning
@ssl_context.verify_hostname = false
else
ssl_host_address = @address
end
debug "starting SSL for #{conn_addr}:#{conn_port}..."
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
s.sync_close = true
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
if @ssl_session and
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
s.session = @ssl_session
end
ssl_socket_connect(s, @open_timeout)
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
s.post_connection_check(@address)
end
debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
end
@socket = BufferedIO.new(s, read_timeout: @read_timeout,
write_timeout: @write_timeout,
continue_timeout: @continue_timeout,
debug_output: @debug_output)
@last_communicated = nil
on_connect
rescue => exception
if s
debug "Conn close because of connect error #{exception}"
s.close
end
raise
end # File lib/net/http.rb, line 2547 def debug(msg) return unless @debug_output @debug_output << msg @debug_output << "\n" end
Добавляет сообщение в отладочный вывод
# File lib/net/http.rb, line 1775 def do_finish @started = false @socket.close if @socket @socket = nil end
# File lib/net/http.rb, line 1635 def do_start connect @started = true end
# File lib/net/http.rb, line 1934
def edit_path(path)
if proxy?
if path.start_with?("ftp://") || use_ssl?
path
else
"http://#{addr_port}#{path}"
end
else
path
end
end # File lib/net/http.rb, line 2479
def end_transport(req, res)
@curr_http_version = res.http_version
@last_communicated = nil
if @socket.closed?
debug 'Conn socket closed'
elsif not res.body and @close_on_empty_response
debug 'Conn close'
@socket.close
elsif keep_alive?(req, res)
debug 'Conn keep-alive'
@last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
else
debug 'Conn close'
@socket.close
end
end # File lib/net/http.rb, line 2496
def keep_alive?(req, res)
return false if req.connection_close?
if @curr_http_version <= '1.0'
res.connection_keep_alive?
else # HTTP/1.1 or later
not res.connection_close?
end
end # File lib/net/http.rb, line 1757 def on_connect end
# File lib/net/http.rb, line 2390
def send_entity(path, data, initheader, dest, type, &block)
res = nil
request(type.new(path, initheader), data) {|r|
r.read_body dest, &block
res = r
}
res
end Выполняет запрос, использующий представление, и возвращает его тело.
# File lib/net/http.rb, line 2520
def sspi_auth(req)
n = Win32::SSPI::NegotiateAuth.new
req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
# Some versions of ISA will close the connection if this isn't present.
req["Connection"] = "Keep-Alive"
req["Proxy-Connection"] = "Keep-Alive"
res = transport_request(req)
authphrase = res["Proxy-Authenticate"] or return res
req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
rescue => err
raise HTTPAuthenticationError.new('HTTP authentication failed', err)
end # File lib/net/http.rb, line 2505
def sspi_auth?(res)
return false unless @sspi_enabled
if res.kind_of?(HTTPProxyAuthenticationRequired) and
proxy? and res["Proxy-Authenticate"].include?("Negotiate")
begin
require 'win32/sspi'
true
rescue LoadError
false
end
else
false
end
end # File lib/net/http.rb, line 2401
def transport_request(req)
count = 0
begin
begin_transport req
res = catch(:response) {
begin
req.exec @socket, @curr_http_version, edit_path(req.path)
rescue Errno::EPIPE
# Failure when writing full request, but we can probably
# still read the received response.
end
begin
res = HTTPResponse.read_new(@socket)
res.decode_content = req.decode_content
res.body_encoding = @response_body_encoding
res.ignore_eof = @ignore_eof
end while res.kind_of?(HTTPInformation)
res.uri = req.uri
res
}
res.reading_body(@socket, req.response_body_permitted?) {
if block_given?
count = max_retries # Don't restart in the middle of a download
yield res
end
}
rescue Net::OpenTimeout
raise
rescue Net::ReadTimeout, IOError, EOFError,
Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT,
# avoid a dependency on OpenSSL
defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
Timeout::Error => exception
if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
count += 1
@socket.close if @socket
debug "Conn close because of error #{exception}, and retry"
retry
end
debug "Conn close because of error #{exception}"
@socket.close if @socket
raise
end
end_transport req, res
res
rescue => exception
debug "Conn close because of error #{exception}"
@socket.close if @socket
raise exception
end # File lib/net/http.rb, line 1919 def unescape(value) require 'cgi/util' CGI.unescape(value) end
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.