背景
Rubyの標準ライブラリであるnet/http
を用いたHTTPリクエストって、Net::HTTP.new
したりNet::HTTP::Get.new
したりhttp.start {...}
したり色々と実装が面倒臭いなとずっと思っていたんですが、実は1行で書けることを知ったので open-uri
との比較も含めて少しまとめてみました。
環境
- Ruby 2.6.0
目次
- 一番シンプルな方法
- リクエストヘッダを指定する方法
- Basic認証を使う方法
- Proxyを挟む方法
-
open-uri
を使う方法
一番シンプルな方法
GET
require "net/http"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)
response.code # status code
response.body # response body
ポイント
-
Net::HTTP.get_response(uri)
の引数はURI
クラスのインスタンスのみ。文字列のURLを入れるとNoMethodError: undefined method 'hostname'
とかいうエラーが返る。 - response.code は数字が文字列型で返ってくる(
"200"
みたいな)。 - response.body は文字列型なので、JSONレスポンスの場合はパースする必要がある。
POST
require "net/http"
params = { title: "my task" }
uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
response = Net::HTTP.post_form(uri, params)
response.code # status code
response.body # response body
ポイント
-
Net::HTTP.post_form
第一引数にURI
クラスのインスタンス、第二引数にハッシュ形式でリクエストボディを渡す。 -
Content-Type
はapplication/x-www-form-urlencoded
形式になる。 - params の中に File オブジェクトを入れてみたが、文字列に変換されてしまった。
リクエストヘッダを指定する方法
GET
シンプルな書き方
require "net/http"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json" }
response = http.get(uri.path, headers)
response.code # status code
response.body # response body
よく紹介される書き方
require "net/http"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json" }
req = Net::HTTP::Get.new(uri.path)
req.initialize_http_header(headers)
response = http.request(req)
response.code # status code
response.body # response body
ポイント
-
Net::HTTP.new
の第一引数にホスト名、第二引数にポートを渡す。 - httpsで始まるURLにアクセスする場合は
Net::HTTP#use_ssl=
にtrue
を渡す。 -
Net::HTTP#get
の第一引数にパス名、第二引数にリクエストヘッダを渡す。 -
Net::HTTP::Get
を使う場合は、初期化時の第一引数にはパス名を渡し、Net::HTTP::Get#initialize_http_header
にハッシュを渡せばリクエストヘッダを指定できる。 -
Net::HTTP::Get#[]=
でもヘッダを指定できる。-
req["Content-Type"] = "application/json"
みたいな。
-
POST
シンプルな書き方
require "net/http"
require "json"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
params = { name: "Takuya" }
headers = { "Content-Type" => "application/json" }
response = http.post(uri.path, params.to_json, headers)
response.code # status code
response.body # response body
よく紹介される書き方
require "net/http"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
params = { name: "Nobuto" }
headers = { "Content-Type" => "application/json" }
req = Net::HTTP::Post.new(uri.path)
req.set_form_data(params)
req.initialize_http_header(headers)
response = http.request(req)
response.code # status code
response.body # response body
ポイント
-
Net::HTTP#post
の第一引数にパス名、第二引数にリクエストボディ、第三引数にリクエストヘッダを渡す。 -
Net::HTTP#post
を使う場合、リクエストボディは文字列を渡す。 -
Net::HTTP::Post#set_form_data
を使う場合、リクエストボディはハッシュを渡す。 -
Content-Type
を指定しなければ自動でapplication/x-www-form-urlencoded
が指定される。
Basic認証を利用する方法
URIオブジェクトを使う方法
require "net/http"
uri = URI.parse("https://username:password@jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)
response.code # status code
response.body # response body
ポイント
-
URI.parse
に渡すURLをプロトコル://ユーザー名:パスワード@ホスト名・パス名
形式で書けばOKなので、多分これが一番シンプル。
Net::HTTP::Get#basic_auth
を使う方法
require "net/http"
username, password = "username", "password"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
req = Net::HTTP::Get.new(uri.path)
req.basic_auth(username, password)
response = http.request(req)
response.code # status code
response.body # response body
Proxyを挟む方法
require "net/http"
base_uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
proxy_uri = URI.parse("http://username:password@proxy-server.com")
http = Net::HTTP.new(base_uri.host, base_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.username, proxy_uri.password)
http.use_ssl = base_uri.scheme === "https"
response = http.get(base_uri.path)
response.code # status code
response.body # response body
ポイント
-
Net::HTTP.new
の第三引数以降にプロキシサーバーのホスト名、ポート、ユーザー名、パスワードを渡せば、他は通常のHTTPリクエストと同様に書ける。
Net::HTTPResponse
について
余談ではあるが、レスポンスとして返ってくるNet::HTTPResponse
オブジェクトのメソッドについて見てみたい。
Net::HTTPResponse#body
-> String
- 文字列型でレスポンスボディを返す。
Net::HTTPResponse#code
-> String
- 文字列型でステータスコードを返す。
Net::HTTPResponse#http_version
-> String
- 文字列型でHTTPのバージョンを返す。
Net::HTTPResponse#message
-> String
- 文字列型でステータスコードのメッセージを返す。
Net::HTTPResponse#value
-> nil
- レスポンスコードが2xxの場合は
nil
を返す。 - レスポンスコードが3xxの場合は例外
HTTPRetriableError
をraise
する - レスポンスコードが4xxの場合は例外
HTTPServerException
をraise
する - レスポンスコードが5xxの場合は例外
HTTPFatalError
をraise
する - レスポンスコードが1xxもしくは未知のコードの場合は例外
HTTPError
をraise
する
require "net/http"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)
p response.code # -> "200"
p response.body # -> "{ \"userId\": 1, \"id\": 1, \"title\": \"delectus aut autem\", \"completed\": false}"
p response.http_version # -> "1.1"
p response.message # -> "OK"
p response.value # -> nil
なんで#value
ってプロパティのようなメソッド名なのに例外をraise
するっていう処理内容なのかちょっと謎。
open-uri
を使う方法
Kernel.#open
を使う方法
require "open-uri"
open("https://jsonplaceholder.typicode.com/todos/1").read # response body
URI#open
を使う方法
require "open-uri"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
uri.open.read # response body
リクエストヘッダを指定する方法
require "open-uri"
open("https://jsonplaceholder.typicode.com/todos/1",
"User-Agent" => "Ruby/#{RUBY_VERSION}"
).read # response body
ポイント
-
open-uri
はGETリクエストのみ対応。 -
open-uri
をrequire
するとURI
にURI#open
メソッドが追加される。 -
open
メソッドの第二引数以降にキーワード引数形式でリクエストヘッダを指定できる。 - ステータスコードが2xxでなかった場合には
OpenURI::HTTPError
をraise
する。
感想
- 何の変哲も無いGET/POSTリクエストについては
Net::HTTP.get_response
やNet::HTTP.post_form
がシンプルなので積極的に使っていきたい。 - ちょっとカスタマイズする必要がある場合は
Net::HTTP#get
やNet::HTTP#post
を使う。ほとんどの場合Net::HTTP::Get
やNet::HTTP::Post
を使う必要なさそう。 - Rails環境では
net/http
がrequire
なしで実行できる一方でopen-uri
はrequire
が必要なので、特に理由が無ければ前者を使っていきたい。