net/http.rb

このライブラリについて

汎用データ転送プロトコル HTTP を扱うライブラリです。 実装は [RFC2616] <URL:http://www.ietf.org/rfc/rfc2616.txt>[外部] に 基いています。

使用例

ウェブサーバからドキュメントを得る (GET)

require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http|
  response , = http.get('/index.html')
  puts response.body
}

また以下は同じ意味で短く書いたものです。

require 'net/http'
Net::HTTP.get_print 'some.www.server', '/index.html'

フォームの情報を送信する (POST)

require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http|
    response , = http.post( '/cgi-bin/any.rhtml',
                            'querytype=subject&target=ruby' )
}

(参照: フォームの値の区切り文字について[外部])

プロクシ経由のアクセス

Net::HTTP のクラスメソッド Net::HTTP.Proxy は、常にプロクシ経由で 接続するような動作をする、新しいクラスを作成して返します。このクラスは Net::HTTP を継承しているので Net::HTTP と全く同じように使えます。

require 'net/http'

$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 自身を返すので 上のコードのように書いておけばプロクシなしの場合にも対応できます。

リダイレクトに対応する

require 'uri'
require 'net/http'
Net::HTTP.version_1_1

uri = URI.parse 'http://www.ruby-lang.org/'
begin
  Net::HTTP.start( uri.host, uri.port ) {|http|
    response , = http.get(uri.request_uri)
    print response.body
  }
rescue Net::ProtoRetriableError => err
  uri = URI.parse err.response['location']
  retry
end

実際にはリダイレクトの無限ループに対処するなどの処理が必要となります。

Ruby 1.6.7 未満の環境では URI クラスが標準添付されていないので、別途調 達するか、あるいはいいかげんながら以下のようにすれば良いでしょう。

require 'net/http'
Net::HTTP.version_1_1

host = 'www.ruby-lang.org'
path = '/'
begin
  Net::HTTP.start( host, 80 ) {|http|
    response , = http.get(path)
    print response.body
  }
rescue Net::ProtoRetriableError => err
  if m = %r<http://([^/]+)>.match( err.response['location'] ) then
    host = m[1].strip
    path = m.post_match
    retry
  end
end

Basic 認証

require 'net/http'

Net::HTTP.start( 'auth.some.domain' ) {|http|
    response , = http.get( '/need-auth.cgi',
            'Authorization' => 'Basic ' + ["#{account}:#{password}"].pack('m').strip )
    print response.body
}

バージョン 1.2 (Ruby 1.7 以降に添付) では次のように書けます。

require 'net/http'

req = Net::HTTP::Get.new('/need-auth.cgi')
req.basic_auth 'account', 'password'
Net::HTTP.start( 'auth.some.domain' ) {|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)... }

この機能はスレッドセーフではありません。

class Net::HTTP

クラスメソッド

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 )

常に指定されたプロクシに接続するクラスを作成し返します。 このクラスは Net::HTTP を継承しているので Net::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 )
post( path, data, header = nil ) {|str| .... }

サーバ上の path にあるエンティティに対し文字列 data を 送ります。レスポンスは << メソッドを使って dest に書き こまれます。header は get メソッドと同じです。 HTTPResponse オブジェクトと dest の配列を返します。

イテレータとして呼びだされたときはエンティティボディを少しづつ ブロックに与えます。

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 プロトコルに関連した例外は発生させません。

class Net::HTTPReqeuest

HTTP リクエストを抽象化するクラス。Net::HTTPRequest は抽象クラス なので実際には下位クラスの Net::HTTP::Get, Post, Head, Put を使用 してください。

クラスメソッド

new

HTTP リクエストオブジェクトを生成します。

メソッド

self[ key ]

key ヘッダフィールドの文字列。 key は大文字小文字を区別しません。

self[ key ] = val

key ヘッダフィールドに val をセットします。 key は大文字小文字を区別しません。

each {|name, val| .... }

ヘッダ名とその値に対するくりかえし。ヘッダ名は小文字で統一されます。

basic_auth( account, password )

Authrization: ヘッダを basic auth 用にセットします。

range

Range: ヘッダの示す範囲を Range オブジェクトで返します。

range = r
set_range( i, len )

範囲を指定してエンティティを取得するためのヘッダ Range: をセットします。 r は Range オブジェクト、i, len は始点と長さです。

content_length

Content-Length: ヘッダの値 (整数)。

content_range

Content-Range: ヘッダの値 (Range)。

class Net::HTTPResponse

HTTP レスポンスのクラスです。 引数がヘッダフィールド名である場合、大文字小文字を区別しません。

メソッド

self[ key ]

key ヘッダフィールド(文字列)を返します。 たとえばキー 'content-length' に対しては '2048' のような 文字列が得られます。key は大文字小文字を区別しません。

self[ key ] = val

key ヘッダフィールドを value に設定します。 key は大文字小文字を区別しません。

key?( key )

key というヘッダフィールドがあれば真。 key は大文字小文字を区別しません。

each {|name,value| .... }

すべてのヘッダフィールド名とその値のペアに対するくりかえし。

canonical_each {|name,value| .... }

ヘッダフィールドの正式名とその値のペアに対して繰り返します。

code

HTTP のリザルトコードです。例えば '302' などです。

message

HTTP サーバがリザルトコードに付加して返すメッセージです。 例えば 'Not Found' などです。

read_body( dest = '' )

エンティティボディを取得し dest に << メソッドを使って書きこみます。 同じ HTTPResponse オブジェクトに対して二回以上呼ばれた場合、 二回目からはなにもせずに一回目の返り値をそのまま返します。

read_body {|str| .... }

エンティティボディを少しづつ取得して順次ブロックに与えます。

body

エンティティボディです。read_body を呼んでいればその引数 dest、 呼んでいなければエンティティボディを文字列として読みこんで返します。

例外

get、head、post メソッドで発生する HTTP プロトコル関連の例外として、 以下に挙げるものがあります。 ここに挙げる例外クラスの親クラスはすべて Net::ProtocolError クラスで、 response メソッドによってエラーの原因となったレスポンスオブジェクトを 得ることができます。

フォームの値の区切り文字について

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 ライブラリではどちらもサポートしていますので、 cgi.rb を用いてCGIスクリプトを書く場合はこれらの違いを 気にする必要はないでしょう。