汎用データ転送プロトコル HTTP を扱うライブラリです。 実装は [RFC2616] <URL:http://www.ietf.org/rfc/rfc2616.txt>[外部] に基きます。
require 'net/http' Net::HTTP.version_1_2 # おまじない Net::HTTP.start('www.example.com', 80) {|http| response = http.get('/index.html') puts response.body }
また以下は同じ意味で短く書いたものです。
require 'net/http' Net::HTTP.version_1_2 # おまじない Net::HTTP.get_print 'www.example.com', '/index.html'
require 'net/http' Net::HTTP.version_1_2 # おまじない Net::HTTP.start('www.example.com', 80) {|http| response = http.post('/cgi-bin/somecgi.rb', 'querytype=subject&target=ruby') }
(参照: フォームの値の区切り文字について)
Net::HTTP のクラスメソッド Net::HTTP.Proxy は、常にプロクシ経由で 接続するような動作をする、新しいクラスを作成して返します。このクラスは Net::HTTP を継承しているので Net::HTTP と全く同じように使えます。
require 'net/http' Net::HTTP.version_1_2 # おまじない $proxy_addr = 'your.proxy.addr' $proxy_port = 8080 : Net::HTTP::Proxy($proxy_addr, $proxy_port).start( 'some.www.server' ) {|http| # always connect to your.proxy.addr:8080 : }
また Net::HTTP.Proxy は第一引数が nil だと Net::HTTP 自身を返すので 上のコードのように書いておけばプロクシなしの場合にも対応できます。
以下のメソッド fetch はリダイレクトに対応しています。 limit 回数以上リダイレクトしたらエラーにします。
require 'uri' require 'net/http' Net::HTTP.version_1_2 # おまじない def fetch( uri_str, limit = 10 ) # 適切な例外クラスに変えるべき 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 print fetch('http://www.ruby-lang.org')
Ruby 1.6.7 未満には URI クラスが標準添付されていないので、別途調達するか、 あるいはいいかげんながら以下のようにしてください。
require 'net/http' Net::HTTP.version_1_2 # おまじない def fetch( uri_str, limit = 10 ) # 適切な例外クラスに変えるべき raise ArgumentError, 'http redirect too deep' if limit == 0 response = Net::HTTP.get_response(*split_uri(uri_str)) case response when Net::HTTPSuccess then response when Net::HTTPRedirection then fetch(response['location'], limit - 1) else response.error! end end def split_uri( uri_str ) m = %r<http://([^/]+)>.match(uri_str) or raise ArgumentError, "cannot parse URI: #{uri_str}" host = m[1].strip path = m.post_match path = '/' if path.empty? return host, path end print fetch('http://www.ruby-lang.org')
require 'net/http' Net::HTTP.version_1_2 # おまじない req = Net::HTTP::Get.new('/need-auth.cgi') req.basic_auth 'account', 'password' Net::HTTP.start('www.example.com') {|http| response = http.request(req) print response.body }
Ruby 1.6 に入っているのが http.rb 1.1 で 1.7 以降が 1.2 ですが、 この間ではかなり大きく仕様が変わります。そこで突然に仕様を変更 するのでなく、両方の実装を並存させる時期を設けることにしました。
メソッド HTTP.version_1_2、HTTP.version_1_1 を呼ぶと そのあとに生成される Net::HTTP オブジェクトはそれぞれの バージョンの仕様で動作するようになります。以下は使用例です。
# example Net::HTTP.start {|http1| ...(http1 has 1.2 features)... } Net::HTTP.version_1_1 Net::HTTP.start {|http2| ...(http2 has 1.1 features)... } Net::HTTP.version_1_2 Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
つまり Ruby 1.6 でも Net::HTTP.version_1_2 を呼べば 1.2 の挙動になりますし、 大半のメソッドは呼べます (Ruby 1.8 でもメソッドが増えているので全てではありません)。 Ruby 1.8 でも Net::HTTP.version_1_1 を呼べば元の挙動にできるので、後方互換性を 保つことができます。
ただし、この機能はスレッドセーフではありません。 つまり、複数スレッドでそれぞれに version_1_1 や version_1_2 を呼んだ場合、 次に生成する Net::HTTP オブジェクトがどちらのバージョンになるかは保証できません。 アプリケーション全体でどちらかのバージョンに固定する必要があります。
なおどちらを使うかですが、これから書くなら断然 version_1_2 です。 require 'net/http' 直後に Net::HTTP.version_1_2 を呼んで 1.1 のことは忘れてください。
new( address, port = 80, proxy_addr = nil, proxy_port = nil )
新しい HTTP オブジェクトを生成します。address は HTTP サーバーの FQDN で、 port は接続するポート番号です。このメソッドではまだ接続はしません。
proxy_addr を与えるとプロクシを介して接続するオブジェクトを生成します。
start( address, port = 80, proxy_addr = nil, proxy_port = nil )
start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
以下と同じです。
Net::HTTP.new(address, port, proxy_addr, proxy_port).start(&block)
get( address, path, port = 80 )
ホスト address の port 番ポートに接続して path の表現する エンティティボディを取得し、文字列で返します。
get_print( address, path, port = 80 )
ホスト address の port 番ポートに接続して path の表現する エンティティボディを取得したうえ、$stdout に << で出力します。
Proxy( address, port = 80 )
Proxy 経由で http サーバに接続するためのクラスを作成し返します。 このクラスは Net::HTTP を継承しているので Net::HTTP と全く 同じように使えます。指定されたプロクシを常に経由して http サーバ に接続します。
address が nil のときは Net::HTTP クラスをそのまま返します。
# example proxy_class = Net::HTTP::Proxy( 'proxy.foo.org', 8080 ) : proxy_class.start( 'www.ruby-lang.org' ) {|http| # connecting proxy.foo.org:8080 : }
proxy_class?
自身が (Proxy メソッドによって作成された) プロクシ用のクラスならば真。
port
HTTP のデフォルトポート (80)。
start
start {|http| .... }
TCP コネクションを張り、HTTP セッションを開始します。 すでにセッションが開始していたら例外 IOError を発生します。
イテレータとして呼ばれた時はブロックの間だけセッションを接続し、 ブロック終了とともに自動的にセッションを閉じます。
active?
HTTP セッションが開始されていたら真。
address
接続するアドレス
port
接続するポート番号
open_timeout
open_timeout=(n)
接続時に待つ最大秒数。この秒数たってもコネクションが 開かなければ例外 TimeoutError を発生します。
read_timeout
read_timeout=(n)
読みこみ (read(1) 一回) でブロックしてよい最大秒数。 この秒数たっても読みこめなければ例外 TimeoutError を発生します。
finish
HTTP セッションを終了します。セッション開始前にこのメソッドが 呼ばれた場合は例外 IOError を発生します。
proxy?
プロクシを介して接続するなら真。
proxy_address
プロクシ経由で接続する HTTP オブジェクトならプロクシのアドレス。 そうでないなら nil。
proxy_port
プロクシ経由で接続する HTTP オブジェクトならプロクシのポート。 そうでないなら nil。
get( path, header = nil )
get( path, header = nil ) {|str| .... }
サーバ上の path にあるエンティティを取得します。また header が nil でなければ、リクエストを送るときにその内容を HTTP ヘッダとして書き こみます。header はハッシュで、「ヘッダ名 => 内容」のような形式で なければいけません。
戻り値は、バージョン 1.1 では HTTPResponse とエンティティボディ文字列の 二要素の配列です。1.2 では HTTPResponse ただひとつのみです。この場合、 エンティティボディは response.body で得られます。
ブロックとともに呼ばれた時はエンティティボディを少しづつブロックに 与えます。
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合 HTTPResponse は例外オブジェクトから err.response で得ることができます。 一方 1.2 では全く例外を発生しません。
# version 1.1 (bundled with Ruby 1.6) response, body = http.get( '/index.html' ) # version 1.2 (bundled with Ruby 1.7 or later) response = http.get( '/index.html' ) # compatible in both version response , = http.get( '/index.html' ) response.body # using block File.open( 'save.txt', 'w' ) {|f| http.get( '/~foo/', nil ) do |str| f.write str end }
head( path, header = nil )
サーバ上の path にあるエンティティのヘッダのみを取得します。 また header が nil でなければリクエストを送るときにその内容を HTTP ヘッダとして書きこみます。header はハッシュで、 「ヘッダ名 => 内容」のような形式でなければいけません。
HTTPResponse オブジェクトを返します。
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合 HTTPResponse は例外オブジェクトから err.response で得ることができます。 一方 1.2 では全く例外を発生しません。
response = nil Net::HTTP.start( 'some.www.server', 80 ) {|http| response = http.head( '/index.html' ) } p response['content-type']
post( path, data, header = nil, dest = nil )
post( path, data, header = nil ) {|str| .... }
サーバ上の path にあるエンティティに対し文字列 data を 送ります。
戻り値は get と同じように、バージョン 1.1 では HTTPResponse と エンティティボディ文字列の 二要素の配列です。1.2 では HTTPResponse ただひとつのみです。この場合、エンティティボディは response.body で得られます。
header は get メソッドと同じです。
dest を与えた場合には、レスポンスは << メソッドを使って dest に書きこまれます。 dest には << メソッドが定義されたオブジェクト、通常 String オブジェクトか Array オブジェクトを与えます。この dest は戻り値の HTTPResponse オブジェクトの body にもなります。
ブロックと一緒に呼びだされたときはエンティティボディを少しづつ文字列として ブロックに与えます。このとき戻り値の HTTPResponse オブジェクトは有効な body を 持ちません。
dest とブロックを同時に与えてはいけません。同時に与えた場合は例外 ArgumentError を投げます。
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合 HTTPResponse は例外オブジェクトから err.response で得ることができます。 一方 1.2 では全く例外を発生しません。
# version 1.1 response, body = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) # version 1.2 response = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) # compatible in both version response , = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) # using block File.open( 'save.html', 'w' ) {|f| http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) do |str| f.write str end }
request_get( path, header = nil )
request_get( path, header = nil ) {|response| .... }
path にあるエンティティを取得します。HTTPResponse オブジェクトを返します。
ブロックとともに呼び出されたときは、ブロック実行中は接続を 維持したまま HTTPResponse オブジェクトをブロックに渡します。
このメソッドは HTTP プロトコルに関連した例外は発生させません。
# example response = http.request_get( '/index.html' ) p response['content-type'] puts response.body # body is already read # using block http.request_get( '/index.html' ) {|response| p response['content-type'] response.read_body do |str| # read body now print str end }
request_post( path, data, header = nil )
request_post( path, data, header = nil ) {|response| .... }
path にあるエンティティを取得します。HTTPResponse オブジェクトを返します。
ブロックとともに呼び出されたときは、ボディを読みこむ前に HTTPResponse オブジェクトをブロックに渡します。
このメソッドは HTTP プロトコルに関連した例外は発生させません。
# example response = http.post2( '/cgi-bin/nice.rb', 'datadatadata...' ) p response.status puts response.body # body is already read # using block http.post2( '/cgi-bin/nice.rb', 'datadatadata...' ) {|response| p response.status p response['content-type'] response.read_body do |str| # read body now print str end }
request( request [, data] )
request( request [, data] ) {|response| .... }
HTTPResquest オブジェクト request を送信します。POST/PUT の時は data も 与えられます (POST/PUT 以外で data を与えると ArgumentError を発生します)。
ブロックとともに呼びだされたときはボディを読みこまずに HTTPResponse オブジェクトをブロックに与えます。
このメソッドは HTTP プロトコルに関連した例外は発生させません。
HTTP リクエストを抽象化するクラス。Net::HTTPRequest は抽象クラス なので実際には下位クラスの Net::HTTP::Get, Post, Head, Put を使用 してください。
new(path)
HTTP リクエストオブジェクトを生成します。リクエストする path を文字列で与える。
self[ key ]
key ヘッダフィールドの文字列。 key は大文字小文字を区別しません。
self[ key ] = val
key ヘッダフィールドに val をセットします。 key は大文字小文字を区別しません。
add_header(key, val)
key ヘッダフィールドに val をセットします。
basic_auth( account, password )
Authrization: ヘッダを basic auth 用にセットします。
body
body=(str)
サーバに送るリクエストのエンティティボディを文字列で設定します。
body_stream
body_stream=
サーバに送るリクエストのエンティティボディを IO オブジェクトなどの ストリームで設定します。read(size) メソッドが定義されている必要があります。
each {|name, val| .... }
ヘッダ名とその値に対するくりかえし。ヘッダ名は小文字で統一されます。
delete(key)
key ヘッダフィールドを削除します。
content_length
Content-Length: ヘッダの値 (整数)。
content_range
Content-Range: ヘッダの値 (Range)。
method
リクエストの HTTP メソッドを文字列で返します。
path
リクエストする path を文字列で返します。
range
Range: ヘッダの示す範囲を Range オブジェクトで返します。
range = r
set_range( i, len )
範囲を指定してエンティティを取得するためのヘッダ Range: をセットします。 r は Range オブジェクト、i, len は始点と長さです。
request_body_permitted?
リクエストにエンティティボディを一緒に送ることが許されている HTTP メソッド (POST など)の場合真を返します。
response_body_permitted?
サーバからのレスポンスにエンティティボディを含むことが許されている HTTP メソッド (GET, POST など)の場合真を返します。
HTTP レスポンスのクラスです。 引数がヘッダフィールド名である場合、大文字小文字を区別しません。
self[ key ]
key ヘッダフィールド(文字列)を返します。 たとえばキー 'content-length' に対しては '2048' のような 文字列が得られます。key は大文字小文字を区別しません。
self[ key ] = val
key ヘッダフィールドを value に設定します。 key は大文字小文字を区別しません。
body
エンティティボディです。read_body を呼んでいればその引数 dest、 呼んでいなければエンティティボディを文字列として読みこんで返します。
canonical_each {|name,value| .... }
ヘッダフィールドの正式名とその値のペアに対して繰り返します。
code
HTTP のリザルトコードです。例えば '302' などです。
each {|name,value| .... }
すべてのヘッダフィールド名とその値のペアに対するくりかえし。
key?( key )
key というヘッダフィールドがあれば真。 key は大文字小文字を区別しません。
http_version
サーバがサポートしている HTTP のバージョンを文字列で返す。
message
HTTP サーバがリザルトコードに付加して返すメッセージです。 例えば 'Not Found' などです。
read_body( dest = '' )
エンティティボディを取得し dest に << メソッドを使って書きこみます。 同じ HTTPResponse オブジェクトに対して二回以上呼ばれた場合、 二回目からはなにもせずに一回目の戻り値をそのまま返します。
read_body {|str| .... }
エンティティボディを少しづつ取得して順次ブロックに与えます。
get、head、post メソッドで発生する HTTP プロトコル関連の例外として、 以下に挙げるものがあります。 ここに挙げる例外クラスの親クラスはすべて Net::ProtocolError クラスで、 response メソッドによってエラーの原因となったレスポンスオブジェクトを 得ることができます。
ProtoRetriableError
HTTP ステータスコード 3xx を受け取った時に発生します。 リソースが移動したなどの理由により、リクエストを完了させるには更な るアクションが必要になります。
ProtoFatalError
HTTP ステータスコード 4xx を受け取った時に発生します。 クライアントのリクエストに誤りがあるか、サーバにリクエストを拒否さ れた(認証が必要、リソースが存在しないなどで)ことを示します。
ProtoServerError
HTTP ステータスコード 5xx を受け取った時に発生します。 サーバがリクエストを処理中にエラーが発生したことを示します。
ProtoUnknownError
プロトコルのバージョンが上がった、あるいはライブラリのバグなどで、 ライブラリが対応していない状況が発生しました。
POSTで application/x-www-form-urlencoded として複数のフォームの値を送る場合、 現在広く行なわれているのは、 name0=value0&name1=value1 のようにアンパサンド `&' で区切るやりかたです。 この方法は、RFC1866 Hypertext Markup Language - 2.0 で初めて公式に登場し、 HTML 4.01 Specification の 17.13.4 Form content types[外部] でもそのように書かれています。
ところが、同じ HTML 4.01 Specification の B.2.2 Ampersands in URI attribute values[外部] では、この `&' がSGMLの文字実体参照で用いられることが指摘されており、 CGIやサーバの実装者に対し `&' の代わりに セミコロン `;' をサポートすることを奨めています。
しかし、実際には `;' を解釈しないCGIやサーバもまだまだ見受けられるため このリファレンスマニュアルでは例として `&' を用いました。
なお Ruby 標準の cgi.rb では & と ; の両方サポートしていますので、 cgi.rb を使って CGI スクリプトを書く場合はこれらの違いを気にする 必要はありません。