An HTTP client API for Ruby.
Net::HTTP provides a rich library which can be used to build HTTP user-agents. For more details about HTTP see [RFC2616](http://www.ietf.org/rfc/rfc2616.txt).
Net::HTTP is designed to work closely with URI. URI::HTTP#host, URI::HTTP#port and URI::HTTP#request_uri are designed to work with Net::HTTP.
If you are only performing a few GET requests you should try OpenURI.
Simple Examples
All examples assume you have loaded Net::HTTP with:
require 'net/http'
This will also require ‘uri’ so you don’t need to require it separately.
The Net::HTTP methods in the following section do not persist connections. They are not recommended if you are performing many HTTP requests.
GET
Net::HTTP.get('example.com', '/index.html') # => String
GET by URI
uri = URI('http://example.com/index.html?count=10') Net::HTTP.get(uri) # => String
GET with Dynamic Parameters
uri = URI('http://example.com/index.html') params = { :limit => 10, :page => 3 } uri.query = URI.encode_www_form(params) res = Net::HTTP.get_response(uri) puts res.body if res.is_a?(Net::HTTPSuccess)
POST
uri = URI('http://www.example.com/search.cgi') res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50') puts res.body
POST with Multiple Values
uri = URI('http://www.example.com/search.cgi') res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50') puts res.body
How to use Net::HTTP
The following example code can be used as the basis of an HTTP user-agent which can perform a variety of request types using persistent connections.
uri = URI('http://example.com/some_path?query=string') Net::HTTP.start(uri.host, uri.port) do |http| request = Net::HTTP::Get.new uri response = http.request request # Net::HTTPResponse object end
Net::HTTP::start immediately creates a connection to an HTTP server which is kept open for the duration of the block. The connection will remain open for multiple requests in the block if the server indicates it supports persistent connections.
If you wish to re-use a connection across multiple HTTP requests without automatically closing it you can use ::new and then call #start and #finish manually.
The request types Net::HTTP supports are listed below in the section “HTTP Request Classes”.
For all the Net::HTTP request objects and shortcut request methods you may supply either a String for the request path or a URI from which Net::HTTP will extract the request path.
Response Data
uri = URI('http://example.com/index.html') res = Net::HTTP.get_response(uri) # Headers res['Set-Cookie'] # => String res.get_fields('set-cookie') # => Array res.to_hash['set-cookie'] # => Array puts "Headers: #{res.to_hash.inspect}" # Status puts res.code # => '200' puts res.message # => 'OK' puts res.class.name # => 'HTTPOK' # Body puts res.body if res.response_body_permitted?
Following Redirection
Each Net::HTTPResponse object belongs to a class for its response code.
For example, all 2XX responses are instances of a Net::HTTPSuccess subclass, a 3XX response is an instance of a Net::HTTPRedirection subclass and a 200 response is an instance of the Net::HTTPOK class. For details of response classes, see the section “HTTP Response Classes” below.
Using a case statement you can handle various types of responses properly:
def fetch(uri_str, limit = 10) # You should choose a better exception. raise ArgumentError, 'too many HTTP redirects' if limit == 0 response = Net::HTTP.get_response(URI(uri_str)) case response when Net::HTTPSuccess then response when Net::HTTPRedirection then location = response['location'] warn "redirected to #{location}" fetch(location, limit - 1) else response.value end end print fetch('http://www.ruby-lang.org')
POST
A POST can be made using the Net::HTTP::Post request class. This example creates a URL encoded POST body:
uri = URI('http://www.example.com/todo.cgi') req = Net::HTTP::Post.new(uri) req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31') res = Net::HTTP.start(uri.hostname, uri.port) do |http| http.request(req) end case res when Net::HTTPSuccess, Net::HTTPRedirection # OK else res.value end
To send multipart/form-data use Net::HTTPHeader#set_form:
req = Net::HTTP::Post.new(uri) req.set_form([['upload', File.open('foo.bar')]], 'multipart/form-data')
Other requests that can contain a body such as PUT can be created in the same way using the corresponding request class (Net::HTTP::Put).
Setting Headers
The following example performs a conditional GET using the If-Modified-Since header. If the files has not been modified since the time in the header a Not Modified response will be returned. See RFC 2616 section 9.3 for further details.
uri = URI('http://example.com/cached_response') file = File.stat 'cached_response' req = Net::HTTP::Get.new(uri) req['If-Modified-Since'] = file.mtime.rfc2822 res = Net::HTTP.start(uri.hostname, uri.port) {|http| http.request(req) } open 'cached_response', 'w' do |io| io.write res.body end if res.is_a?(Net::HTTPSuccess)
Basic Authentication
Basic authentication is performed according to [RFC2617](http://www.ietf.org/rfc/rfc2617.txt).
uri = URI('http://example.com/index.html?key=value') req = Net::HTTP::Get.new(uri) req.basic_auth 'user', 'pass' res = Net::HTTP.start(uri.hostname, uri.port) {|http| http.request(req) } puts res.body
Streaming Response Bodies
By default Net::HTTP reads an entire response into memory. If you are handling large files or wish to implement a progress bar you can instead stream the body directly to an IO.
uri = URI('http://example.com/large_file') Net::HTTP.start(uri.host, uri.port) do |http| request = Net::HTTP::Get.new uri http.request request do |response| open 'large_file', 'w' do |io| response.read_body do |chunk| io.write chunk end end end end
HTTPS
HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.
uri = URI('https://secure.example.com/some_path?query=string') Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http| request = Net::HTTP::Get.new uri response = http.request request # Net::HTTPResponse object end
Or if you simply want to make a GET request, you may pass in an URI object that has an HTTPS URL. Net::HTTP automatically turns on TLS verification if the URI object has a ‘https’ URI scheme.
uri = URI('https://example.com/') Net::HTTP.get(uri) # => String
In previous versions of Ruby you would need to require ‘net/https’ to use HTTPS. This is no longer true.
Proxies
Net::HTTP will automatically create a proxy from the http_proxy environment variable if it is present. To disable use of http_proxy, pass nil for the proxy address.
You may also create a custom proxy:
proxy_addr = 'your.proxy.host' proxy_port = 8080 Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http| # always proxy via your.proxy.addr:8080 }
See Net::HTTP.new for further details and examples such as proxies that require a username and password.
Compression
Net::HTTP automatically adds Accept-Encoding for compression of response bodies and automatically decompresses gzip and deflate responses unless a Range header was sent.
Compression can be disabled through the Accept-Encoding: identity header.
HTTP Request Classes
Here is the HTTP request class hierarchy.
HTTP Response Classes
Here is HTTP response class hierarchy. All classes are defined in Net module and are subclasses of Net::HTTPResponse.
HTTPUnknownResponse |
For unhandled HTTP extensions |
HTTPInformation |
1xx |
HTTPContinue |
100 |
HTTPSwitchProtocol |
101 |
HTTPSuccess |
2xx |
HTTPOK |
200 |
HTTPCreated |
201 |
HTTPAccepted |
202 |
HTTPNonAuthoritativeInformation |
203 |
HTTPNoContent |
204 |
HTTPResetContent |
205 |
HTTPPartialContent |
206 |
HTTPMultiStatus |
207 |
HTTPIMUsed |
226 |
HTTPRedirection |
3xx |
HTTPMultipleChoices |
300 |
HTTPMovedPermanently |
301 |
HTTPFound |
302 |
HTTPSeeOther |
303 |
HTTPNotModified |
304 |
HTTPUseProxy |
305 |
HTTPTemporaryRedirect |
307 |
HTTPClientError |
4xx |
HTTPBadRequest |
400 |
HTTPUnauthorized |
401 |
HTTPPaymentRequired |
402 |
HTTPForbidden |
403 |
HTTPNotFound |
404 |
HTTPMethodNotAllowed |
405 |
HTTPNotAcceptable |
406 |
HTTPProxyAuthenticationRequired |
407 |
HTTPRequestTimeOut |
408 |
HTTPConflict |
409 |
HTTPGone |
410 |
HTTPLengthRequired |
411 |
HTTPPreconditionFailed |
412 |
HTTPRequestEntityTooLarge |
413 |
HTTPRequestURITooLong |
414 |
HTTPUnsupportedMediaType |
415 |
HTTPRequestedRangeNotSatisfiable |
416 |
HTTPExpectationFailed |
417 |
HTTPUnprocessableEntity |
422 |
HTTPLocked |
423 |
HTTPFailedDependency |
424 |
HTTPUpgradeRequired |
426 |
HTTPPreconditionRequired |
428 |
HTTPTooManyRequests |
429 |
HTTPRequestHeaderFieldsTooLarge |
431 |
HTTPUnavailableForLegalReasons |
451 |
HTTPServerError |
5xx |
HTTPInternalServerError |
500 |
HTTPNotImplemented |
501 |
HTTPBadGateway |
502 |
HTTPServiceUnavailable |
503 |
HTTPGatewayTimeOut |
504 |
HTTPVersionNotSupported |
505 |
HTTPInsufficientStorage |
507 |
HTTPNetworkAuthenticationRequired |
511 |
There is also the Net::HTTPBadResponse exception which is raised when there is a protocol error.
Constants
IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/
ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = true
SSL_ATTRIBUTES = [ :ca_file, :ca_path, :cert, :cert_store, :ciphers, :key, :ssl_timeout, :ssl_version, :min_version, :max_version, :verify_callback, :verify_depth, :verify_mode, ]
SSL_IVNAMES = [ :@ca_file, :@ca_path, :@cert, :@cert_store, :@ciphers, :@key, :@ssl_timeout, :@ssl_version, :@min_version, :@max_version, :@verify_callback, :@verify_depth, :@verify_mode, ]
Attributes
[R] | proxy_pass |
User password for accessing proxy. If Net::HTTP does not use a proxy, nil. |
[R] | proxy_user |
User name for accessing proxy. If Net::HTTP does not use a proxy, nil. |
[R] | proxy_port |
Port number of proxy host. If Net::HTTP does not use a proxy, nil. |
[R] | proxy_address |
Address of proxy host. If Net::HTTP does not use a proxy, nil. |
[RW] | verify_mode |
Sets the flags for server the certification verification at beginning of SSL/TLS session. OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable. |
[RW] | verify_depth |
Sets the maximum depth for the certificate chain verification. |
[RW] | verify_callback |
Sets the verify callback for the server certification verification. |
[RW] | max_version |
Sets the maximum SSL version. See OpenSSL::SSL::SSLContext#max_version= |
[RW] | min_version |
Sets the minimum SSL version. See OpenSSL::SSL::SSLContext#min_version= |
[RW] | ssl_version |
Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version= |
[RW] | ssl_timeout |
Sets the SSL timeout seconds. |
[RW] | key |
Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object. (This method is appeared in Michal Rokos’s OpenSSL extension.) |
[RW] | ciphers |
Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers= |
[RW] | cert_store |
Sets the X509::Store to verify peer certificate. |
[RW] | cert |
Sets an OpenSSL::X509::Certificate object as client certificate. (This method is appeared in Michal Rokos’s OpenSSL extension). |
[RW] | ca_path |
Sets path of a CA certification directory containing certifications in PEM format. |
[RW] | ca_file |
Sets path of a CA certification file in PEM format. The file can contain several CA certificates. |
[RW] | close_on_empty_response | |
[RW] | keep_alive_timeout |
Seconds to reuse the connection of the previous request. If the idle time is less than this Keep-Alive Timeout, Net::HTTP reuses the TCP/IP socket used by the previous communication. The default value is 2 seconds. |
[R] | continue_timeout |
Seconds to wait for 100 Continue response. If the HTTP object does not receive a response in this many seconds it sends the request body. The default value is nil. |
[R] | max_retries | |
[R] | write_timeout |
Number of seconds to wait for one block to be written (via one write(2) call). Any number may be used, including Floats for fractional seconds. If the HTTP object cannot write data in this many seconds, it raises a Net::WriteTimeout exception. The default value is 60 seconds. Net::WriteTimeout is not raised on Windows. |
[R] | read_timeout |
Number of seconds to wait for one block to be read (via one read(2) call). Any number may be used, including Floats for fractional seconds. If the HTTP object cannot read data in this many seconds, it raises a Net::ReadTimeout exception. The default value is 60 seconds. |
[RW] | open_timeout |
Number of seconds to wait for the connection to open. Any number may be used, including Floats for fractional seconds. If the HTTP object cannot open a connection in this many seconds, it raises a Net::OpenTimeout exception. The default value is 60 seconds. |
[W] | proxy_pass | |
[W] | proxy_user | |
[W] | proxy_port | |
[W] | proxy_address | |
[W] | proxy_from_env | |
[RW] | local_port |
The local port used to establish the connection. |
[RW] | local_host |
The local host used to establish the connection. |
[R] | port |
The port number to connect to. |
[R] | address |
The DNS host name or IP address to connect to. |
HTTPS request
Hey, guys!
You have one mistake in example code.
uri = URI('https://secure.example.com/some_path?query=string') Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https').start do |http| request = Net::HTTP::Get.new uri.request_uri response = http.request request end
Here HTTP::start method called twice. This code should look like
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http| request = Net::HTTP::Get.new uri.request_uri response = http.request request end
It’s work - I checked.
Re: POST DATA
The ampersand is more common, but the W3C recommends that all web servers support semicolon separators in the place of ampersand separators:
http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2
Testing Net:HTTP connections
You can use this excellent library to stub Net:HTTP connections in your automatic tests: