RubyでGETリクエストやPOSTリクエストした時のメモ

RubyでGETリクエストやPOSTリクエストをする際の色々確認した時のメモ。

# 参考

[library net/http](http://docs.ruby-lang.org/ja/2.3.0/library/net=2fhttp.html)

# 確認用Webサーバーの準備

今回はNode.js(v4.4.4)でWebサーバーを立てHTTPヘッダーやGETパラメーターを確認しました。

まずはNode.jsのインストール

```bash
$curl --silent --location https://rpm.nodesource.com/setup_4.x | bash -
$yum -y install nodejs
```

以下のようなコードを書きます。

```server.js
var http = require('http');

var server = http.createServer(function (req,res) {
  // confirm request
  console.log(`headers: ${JSON.stringify(req.headers)}`);
  console.log(`httpVersion: ${req.httpVersion}`);
  console.log(`method: ${req.method}`);
  console.log(`url: ${req.url}`);

  // response
  res.writeHeader(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify({ 'foo': 'bar'}));
});

server.listen({
  port: 80
});
```

起動及び実行時のログは以下のようになります。

```bash
# 起動
node server.js

# curlでこのサーバーにリクエストした際の標準出力
headers: {"host":"54.238.183.170","user-agent":"curl/7.43.0","accept":"*/*"}
httpVersion: 1.1
method: GET
url: /

# curlでサーバーにリクエスト(パスを変更)した際の標準出力
headers: {"host":"54.238.183.170","user-agent":"curl/7.43.0","accept":"*/*"}
httpVersion: 1.1
method: GET
url: /hogefufa
```


# GETメソッド

## GETリクエストを行って標準出力する

Net::HTTP.get_printを使うことでBodyのみを標準出力します。

```hoge.rb
require 'net/http'

# 以下2つのいずれか

# hostとパスを指定する
Net::HTTP.get_print('54.238.183.170', '/')

# URIを指定する
Net::HTTP.get_print(URI.parse('http://54.238.183.170'))
```

Webサーバー側では以下のように出力されています。

```bash
headers: {"accept-encoding":"gzip;q=1.0,deflate;q=0.6,identity;q=0.3","accept":"*/*","user-agent":"Ruby","host":"54.238.183.170"}
httpVersion: 1.1
method: GET
url: /
```

## GETリクエストを行ってHTTPレスポンスのボディを変数に入れる

HTTPレスポンスのボディを変数に設定する場合には以下のようにします。

```hoge.rb
require 'net/http'
require 'json'

res = Net::HTTP.get('54.238.183.170', '/')
puts res //  {"foo":"bar"}
puts JSON.parse(res)['foo'] // bar
res2 = Net::HTTP.get(URI.parse('http://54.238.183.170'))
puts res2 //  {"foo":"bar"}
```

## HTTPレスポンスのステータスコードやヘッダも見たい

Net::HTTP.getではステータスコードやレスポンスヘッダが取得できないのでNet::HTTP.startを利用してリクエストを行います。

```hoge.rb
require 'net/http'
require 'json'
require 'uri'

url = URI.parse('http://54.238.183.170')
res = Net::HTTP.start(url.host, url.port) do |http|
  http.get('/')
end

puts res.code
puts res.body
res.each_header do |name, val|
  puts "name=#{name}, val=#{val}"
end
```

Net::HTTPResponseが返却されるのでこのオブジェクトから情報を取得します。

```bash
$ruby hoge.rb

200
{"foo":"bar"}
name=content-type, val=application/json
name=date, val=Sat, 21 May 2016 09:08:13 GMT
name=connection, val=keep-alive
name=transfer-encoding, val=chunked
```

# HTTPリクエストヘッダを変更したい

リクエスト時のHTTPリクエストヘッダを変更する場合、以下のようにします。

```hoge.rb
require 'net/http'
require 'json'
require 'uri'

url = URI.parse('http://54.238.183.170')
req = Net::HTTP::Get.new(url.request_uri)
req['Accept'] = 'application/json'

res = Net::HTTP.start(url.host, url.port) do |http|
  http.request(req)
end

puts res.body
```

Net::HTTP::Get.newによってNet::HTTP::Getオブジェクトを生成します。
Net::HTTP::GetクラスはNet::HTTPHeaderモジュールを利用しており、`self[key]->String`と指定することでHTTヘッダを指定します。


以下のようにWebサーバーの標準出力でもHTTPヘッダーが指定されていることを確認できました。

```bash
headers: {"accept-encoding":"gzip;q=1.0,deflate;q=0.6,identity;q=0.3","accept":"application/json","user-agent":"Ruby","host":"54.238.183.170"}
httpVersion: 1.1
method: GET
url: /
```

# リクエストパラメーターをURLエンコードしたい

日本語のリクエストパラメーターを利用する場合にURLエンコードする必要がありますが、その場合以下のようにします。

```hoge.rb
require 'net/http'
require 'json'
require 'uri'

params = URI.encode_www_form({ area: 1, city: 'アイウエオ'})
url = URI.parse("http://54.238.183.170/?#{params}")
req = Net::HTTP::Get.new(url.request_uri)
req['Accept'] = 'application/json'

res = Net::HTTP.start(url.host, url.port) do |http|
  http.request(req)
end

puts res.body
```

Webサーバーは以下のように標準出力されています。

```bash
headers: {"accept-encoding":"gzip;q=1.0,deflate;q=0.6,identity;q=0.3","accept":"application/json","user-agent":"Ruby","host":"54.238.183.170"}
httpVersion: 1.1
method: GET
url: /?area=1&city=%E3%82%A2%E3%82%A4%E3%82%A6%E3%82%A8%E3%82%AA
```

上記がエンコードされているかnkfコマンドを使って確認してみます。

```bash
$echo %E3%82%A2%E3%82%A4%E3%82%A6%E3%82%A8%E3%82%AA |nkf -w --url-input
アイウエオ
```

# POSTメソッド

今までGETメソッドでやったものをNet::HTTP.post_formを利用したり、Net::HTTP::Post.newを利用してオブジェクトを生成すればOKです。

まずはWebサーバーの設定をPOSTメソッド用に変更します。

```server.js
var server = http.createServer(function (req,res) {
  // confirm request
  console.log(`headers: ${JSON.stringify(req.headers)}`);
  console.log(`httpVersion: ${req.httpVersion}`);
  console.log(`method: ${req.method}`);
  console.log(`url: ${req.url}`);
  if (req.method === 'POST' ) {
    var data = '';

    req.on('data', (chunk) => {
      data += chunk;
    });

    req.on('end', () => {
      console.log(`data: ${data}`);

      // response
       res.writeHeader(200, {'Content-Type': 'application/json'});
       res.end(JSON.stringify({ 'foo': 'bar'}));
    });
  }

});

server.listen({
  port: 80
});
```

Rubyのコードは以下のようにします。

```hoge.rb
require 'net/http'
require 'uri'

# POSTするだけ
res = Net::HTTP.post_form(URI.parse('http://54.238.183.170'),{'q' => 'ruby'})
puts res.body

# 詳細
url = URI.parse('http://54.238.183.170/')
req = Net::HTTP::Post.new(url.path)
req.set_form_data({'from' => '2005-01-01', 'to' => '2010-01-01'}, ';')
res = Net::HTTP.new(url.host, url.port).start do |http|
  http.request(req)
end

puts res.code
puts res.body
```

実行するとWebサーバーで以下のような標準出力となります。

```bash
headers: {"accept-encoding":"gzip;q=1.0,deflate;q=0.6,identity;q=0.3","accept":"*/*","user-agent":"Ruby","host":"54.238.183.170","content-type":"application/x-www-form-urlencoded","content-length":"6"}
httpVersion: 1.1
method: POST
url: /
data: q=ruby
headers: {"accept-encoding":"gzip;q=1.0,deflate;q=0.6,identity;q=0.3","accept":"*/*","user-agent":"Ruby","content-type":"application/x-www-form-urlencoded","host":"54.238.183.170","content-length":"29"}
httpVersion: 1.1
method: POST
url: /
data: from=2005-01-01;to=2010-01-01
```

POSTデータが送信できているのが確認できました。