net/http
Go標準ライブラリのHTTPクライアント・サーバーパッケージ。堅牢性、柔軟性、包括的なドキュメントを提供。HTTP/1.1、HTTP/2サポート、詳細な設定オプション、Cookie管理、リダイレクト処理、タイムアウト制御機能を内蔵。外部依存関係不要。
GitHub概要
ruby/ruby
The Ruby Programming Language
スター23,021
ウォッチ1,081
フォーク5,489
作成日:2010年2月27日
言語:Ruby
ライセンス:Other
トピックス
cjitlanguageobject-orientedprogramming-languagerubyruby-languagerust
スター履歴
データ取得日時: 2025/10/22 09:54
ライブラリ
Net::HTTP
概要
Net::HTTPは「Ruby標準ライブラリのHTTPクライアント実装」として開発された、Rubyエコシステムの基盤となるHTTPクライアントライブラリです。Ruby標準ライブラリの一部として長年にわたり安定した動作を提供し、シンプルで直感的なAPIを通じてHTTP通信を実現。RESTful API開発、Webスクレイピング、外部サービス連携など様々な用途で活用され、多くのRuby HTTPライブラリの基盤として機能。標準ライブラリならではの高い信頼性と互換性により、Ruby開発者にとって必須のネットワーキングツールとしての地位を確立しています。
詳細
Net::HTTP 2025年版はRuby標準ライブラリとして30年近い開発実績を持つ成熟したHTTPクライアントライブラリです。Ruby 3.x系での最新機能サポートを維持しながら、後方互換性を重視した設計により幅広いRubyバージョンで一貫した動作を提供。基本的なGET/POST/PUT/DELETEリクエストから、SSL/TLS通信、プロキシサーバー対応、Cookie管理、セッション管理、フォームデータ送信、ファイルアップロード等の高度な機能まで包括的にサポート。シンプルなクラスメソッドAPIと詳細制御可能なインスタンスAPIの両方を提供し、用途に応じた最適な実装方法を選択可能です。
主な特徴
- Ruby標準ライブラリ: 追加インストール不要の標準搭載ライブラリ
- 包括的HTTPサポート: GET、POST、PUT、DELETE、WebDAV等のメソッド対応
- SSL/TLS完全対応: HTTPS通信、証明書検証、暗号化設定
- セッション管理: 効率的な接続プールと永続的接続
- 豊富な認証方式: Basic認証、Digest認証、プロキシ認証
- フォーム処理: マルチパート形式とURL encoded形式の両対応
メリット・デメリット
メリット
- Ruby標準ライブラリのため追加依存関係なしで即座に利用可能
- 30年近い開発実績による圧倒的な安定性と成熟度
- Ruby言語との深い統合により高いパフォーマンスと信頼性を実現
- シンプルで直感的なAPIによる学習コストの低さ
- 豊富な機能により企業レベルのHTTP通信要件に対応
- 他のRuby HTTPライブラリとの高い互換性とエコシステム統合
デメリット
- 同期処理ベースのため大量の並列リクエストに不向き
- 非同期処理には別途em-http-request等の専用ライブラリが必要
- APIの一部が低レベルで、現代的な高級ライブラリと比較して記述量が多い
- JSONレスポンスの自動パースなどの便利機能が標準では未提供
- エラーハンドリングが例外ベースで詳細な制御が必要
- HTTP/2やHTTP/3などの最新プロトコルサポートに制限
参考ページ
書き方の例
インストールと基本セットアップ
# Ruby標準ライブラリのため require のみ
require 'net/http'
require 'uri'
require 'json'
require 'openssl'
# Ruby 3.0以降では明示的なrequireが必要な場合がある
require 'net/http'
# SSL証明書の検証を有効化(推奨)
Net::HTTP.verify_mode = OpenSSL::SSL::VERIFY_PEER
# グローバル設定(オプション)
Net::HTTP.class_eval do
# デフォルトタイムアウト設定
@@default_timeout = 30
def self.default_timeout=(value)
@@default_timeout = value
end
def self.default_timeout
@@default_timeout
end
end
# デバッグ用の詳細ログ出力(開発時のみ)
# Net::HTTP.start('example.com', 80, debug: true)
puts "Net::HTTP version: #{Net::HTTP::VERSION}"
puts "Ruby version: #{RUBY_VERSION}"
基本的なHTTPリクエスト(GET/POST/PUT/DELETE)
require 'net/http'
require 'uri'
require 'json'
# 基本的なGETリクエスト
def simple_get_request
uri = URI('https://api.example.com/users')
begin
response = Net::HTTP.get_response(uri)
puts "Status: #{response.code} #{response.message}"
puts "Headers: #{response.to_hash}"
puts "Body: #{response.body}"
if response.is_a?(Net::HTTPSuccess)
data = JSON.parse(response.body)
puts "Parsed JSON: #{data}"
return data
else
puts "Request failed: #{response.code}"
return nil
end
rescue StandardError => e
puts "Error: #{e.message}"
return nil
end
end
# クエリパラメータ付きGETリクエスト
def get_request_with_params
base_uri = 'https://api.example.com/users'
params = {
page: 1,
limit: 20,
sort: 'created_at',
filter: 'active'
}
# パラメータをクエリ文字列に変換
query_string = URI.encode_www_form(params)
uri = URI("#{base_uri}?#{query_string}")
puts "Request URL: #{uri}"
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(uri)
request['User-Agent'] = 'MyApp/1.0 (Ruby Net::HTTP)'
request['Accept'] = 'application/json'
request['Authorization'] = 'Bearer your-access-token'
response = http.request(request)
case response
when Net::HTTPSuccess
puts "Success: #{response.code}"
JSON.parse(response.body)
when Net::HTTPRedirection
puts "Redirected: #{response['location']}"
# リダイレクト処理
nil
when Net::HTTPClientError
puts "Client Error: #{response.code} - #{response.message}"
nil
when Net::HTTPServerError
puts "Server Error: #{response.code} - #{response.message}"
nil
else
puts "Unknown response: #{response.code}"
nil
end
end
# POSTリクエスト(JSON送信)
def post_json_request
uri = URI('https://api.example.com/users')
user_data = {
name: '田中太郎',
email: '[email protected]',
age: 30,
department: '開発部'
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 30
http.open_timeout = 10
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request['Authorization'] = 'Bearer your-access-token'
request['User-Agent'] = 'MyApp/1.0 (Ruby)'
request.body = JSON.generate(user_data)
begin
response = http.request(request)
puts "POST Response: #{response.code}"
puts "Response Headers: #{response.to_hash}"
if response.code == '201'
created_user = JSON.parse(response.body)
puts "User created successfully: #{created_user}"
return created_user
else
puts "Error creating user: #{response.body}"
return nil
end
rescue Net::TimeoutError => e
puts "Request timeout: #{e.message}"
return nil
rescue StandardError => e
puts "Request error: #{e.message}"
return nil
end
end
# POSTリクエスト(フォームデータ送信)
def post_form_data
uri = URI('https://api.example.com/login')
form_data = {
'username' => 'testuser',
'password' => 'secret123',
'remember_me' => 'true'
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/x-www-form-urlencoded'
request['User-Agent'] = 'MyApp/1.0 (Ruby)'
request.set_form_data(form_data)
response = http.request(request)
puts "Login Response: #{response.code}"
puts "Set-Cookie: #{response['Set-Cookie']}" if response['Set-Cookie']
response
end
# PUTリクエスト(データ更新)
def put_request
uri = URI('https://api.example.com/users/123')
update_data = {
name: '田中次郎',
email: '[email protected]',
age: 31
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer your-access-token'
request.body = JSON.generate(update_data)
response = http.request(request)
if response.is_a?(Net::HTTPSuccess)
puts "User updated successfully"
JSON.parse(response.body)
else
puts "Update failed: #{response.code} - #{response.body}"
nil
end
end
# DELETEリクエスト
def delete_request
uri = URI('https://api.example.com/users/123')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(uri)
request['Authorization'] = 'Bearer your-access-token'
response = http.request(request)
case response.code
when '204'
puts "User deleted successfully"
true
when '404'
puts "User not found"
false
else
puts "Delete failed: #{response.code} - #{response.body}"
false
end
end
# レスポンス詳細分析
def analyze_response(response)
puts "=== Response Analysis ==="
puts "Status: #{response.code} #{response.message}"
puts "HTTP Version: #{response.http_version}"
puts "Content-Type: #{response.content_type}"
puts "Content-Length: #{response.content_length}"
puts "Last-Modified: #{response['Last-Modified']}"
puts "ETag: #{response['ETag']}"
puts "Cache-Control: #{response['Cache-Control']}"
# レスポンスボディの文字エンコーディング
if response.body
puts "Body Encoding: #{response.body.encoding}"
puts "Body Size: #{response.body.bytesize} bytes"
end
puts "========================"
end
# 使用例
simple_get_request
get_request_with_params
post_json_request
post_form_data
put_request
delete_request
高度な設定とカスタマイズ(認証、SSL、セッション等)
require 'net/http'
require 'openssl'
require 'base64'
# Basic認証
def basic_auth_request
uri = URI('https://api.example.com/private')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request.basic_auth('username', 'password')
# または手動でヘッダー設定
# credentials = Base64.strict_encode64("username:password")
# request['Authorization'] = "Basic #{credentials}"
response = http.request(request)
puts "Basic Auth Response: #{response.code}"
response
end
# カスタムヘッダーとタイムアウト設定
def custom_headers_and_timeout
uri = URI('https://api.example.com/data')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
# タイムアウト設定
http.open_timeout = 10 # 接続タイムアウト(秒)
http.read_timeout = 30 # 読み込みタイムアウト(秒)
http.write_timeout = 30 # 書き込みタイムアウト(秒)
http.continue_timeout = 1 # 100-continue タイムアウト(秒)
request = Net::HTTP::Get.new(uri)
# カスタムヘッダー設定
request['User-Agent'] = 'MyApp/1.0 (Ruby Net::HTTP)'
request['Accept'] = 'application/json, application/xml'
request['Accept-Language'] = 'ja-JP, en-US'
request['Accept-Encoding'] = 'gzip, deflate, br'
request['Cache-Control'] = 'no-cache'
request['X-API-Version'] = 'v2'
request['X-Request-ID'] = SecureRandom.uuid
request['X-Client-Info'] = 'Ruby/3.2.0 Net::HTTP/0.4.0'
begin
response = http.request(request)
puts "Custom Request Response: #{response.code}"
# レスポンス圧縮の確認
if response['Content-Encoding']
puts "Content-Encoding: #{response['Content-Encoding']}"
end
response
rescue Net::OpenTimeout => e
puts "Connection timeout: #{e.message}"
nil
rescue Net::ReadTimeout => e
puts "Read timeout: #{e.message}"
nil
end
end
# SSL/TLS設定とクライアント証明書
def ssl_configuration
uri = URI('https://secure-api.example.com/data')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
# SSL設定
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5
# CA証明書の指定
http.ca_file = '/path/to/ca-bundle.crt' # CA証明書ファイル
# http.ca_path = '/path/to/ca-certs/' # CA証明書ディレクトリ
# クライアント証明書設定
http.cert = OpenSSL::X509::Certificate.new(File.read('/path/to/client.crt'))
http.key = OpenSSL::PKey::RSA.new(File.read('/path/to/client.key'), 'key-password')
# 暗号化設定
http.ssl_version = :TLSv1_2 # TLSバージョン指定
http.ciphers = 'HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA'
# SSL証明書の詳細検証(開発環境での検証無効化)
# http.verify_mode = OpenSSL::SSL::VERIFY_NONE # 本番では非推奨
# SSL証明書の検証コールバック
http.verify_callback = proc do |preverify_ok, ssl_context|
if preverify_ok
puts "SSL Certificate verification: OK"
else
puts "SSL Certificate verification failed: #{ssl_context.error_string}"
end
preverify_ok
end
request = Net::HTTP::Get.new(uri)
begin
response = http.request(request)
puts "SSL Request Response: #{response.code}"
# SSL接続情報の表示
puts "SSL Cipher: #{http.peer_cert.to_text}" if http.peer_cert
response
rescue OpenSSL::SSL::SSLError => e
puts "SSL Error: #{e.message}"
nil
end
end
# プロキシサーバー設定
def proxy_configuration
# プロキシ情報
proxy_host = 'proxy.example.com'
proxy_port = 8080
proxy_user = 'proxy_username'
proxy_pass = 'proxy_password'
uri = URI('https://api.example.com/data')
# プロキシ付きHTTP接続
http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port, proxy_user, proxy_pass)
http.use_ssl = true
# プロキシ認証が不要な場合
# http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port)
request = Net::HTTP::Get.new(uri)
begin
response = http.request(request)
puts "Proxy Request Response: #{response.code}"
response
rescue Net::ProxyError => e
puts "Proxy Error: #{e.message}"
nil
end
end
# セッション管理とCookie処理
class HTTPSession
def initialize(base_url)
@uri = URI(base_url)
@cookies = {}
@http = create_http_connection
end
def create_http_connection
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = @uri.scheme == 'https'
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.read_timeout = 30
http.open_timeout = 10
http
end
def get(path, headers = {})
request = Net::HTTP::Get.new(path)
add_headers(request, headers)
add_cookies(request)
response = @http.request(request)
extract_cookies(response)
response
end
def post(path, data = nil, headers = {})
request = Net::HTTP::Post.new(path)
add_headers(request, headers)
add_cookies(request)
if data
if headers['Content-Type'] == 'application/json'
request.body = JSON.generate(data)
else
request.set_form_data(data)
end
end
response = @http.request(request)
extract_cookies(response)
response
end
def login(username, password, login_path = '/login')
login_data = {
username: username,
password: password
}
response = post(login_path, login_data)
if response.is_a?(Net::HTTPSuccess)
puts "Login successful"
true
else
puts "Login failed: #{response.code}"
false
end
end
def close
@http.finish if @http.started?
end
private
def add_headers(request, headers)
default_headers = {
'User-Agent' => 'Ruby HTTPSession/1.0',
'Accept' => 'application/json'
}
default_headers.merge(headers).each do |key, value|
request[key] = value
end
end
def add_cookies(request)
return if @cookies.empty?
cookie_string = @cookies.map { |name, value| "#{name}=#{value}" }.join('; ')
request['Cookie'] = cookie_string
end
def extract_cookies(response)
return unless response['Set-Cookie']
response.get_fields('Set-Cookie').each do |cookie|
# クッキーの解析(簡易版)
cookie_parts = cookie.split(';').first.split('=', 2)
next unless cookie_parts.size == 2
name, value = cookie_parts
@cookies[name.strip] = value.strip
end
end
end
# セッション使用例
def session_example
session = HTTPSession.new('https://api.example.com')
begin
# ログイン
if session.login('testuser', 'password123')
# 認証が必要なAPIの呼び出し
response = session.get('/profile')
puts "Profile Response: #{response.code}"
# データの投稿
post_data = { message: 'Hello from Ruby!' }
response = session.post('/posts', post_data, { 'Content-Type' => 'application/json' })
puts "Post Response: #{response.code}"
end
ensure
session.close
end
end
# 使用例
basic_auth_request
custom_headers_and_timeout
ssl_configuration
proxy_configuration
session_example
エラーハンドリングとリトライ機能
require 'net/http'
require 'uri'
require 'json'
# 包括的なエラーハンドリング
class HTTPClient
class << self
def safe_request(method, url, options = {})
uri = URI(url)
retries = options[:retries] || 3
timeout = options[:timeout] || 30
headers = options[:headers] || {}
body = options[:body]
(retries + 1).times do |attempt|
begin
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.read_timeout = timeout
http.open_timeout = timeout / 3
request = create_request(method, uri, headers, body)
response = http.request(request)
# 成功レスポンスの判定
if response.is_a?(Net::HTTPSuccess)
return parse_response(response, options[:parse_json])
elsif response.is_a?(Net::HTTPServerError) && attempt < retries
puts "Server error (#{response.code}), retrying in #{attempt + 1} seconds..."
sleep(attempt + 1)
next
else
handle_http_error(response)
return nil
end
rescue Net::TimeoutError => e
if attempt < retries
puts "Timeout error, retrying in #{attempt + 1} seconds..."
sleep(attempt + 1)
next
else
puts "Request timeout after #{retries + 1} attempts: #{e.message}"
return nil
end
rescue Net::ConnectionRefused => e
if attempt < retries
puts "Connection refused, retrying in #{(attempt + 1) * 2} seconds..."
sleep((attempt + 1) * 2)
next
else
puts "Connection refused after #{retries + 1} attempts: #{e.message}"
return nil
end
rescue SocketError => e
puts "DNS/Socket error: #{e.message}"
return nil
rescue OpenSSL::SSL::SSLError => e
puts "SSL error: #{e.message}"
return nil
rescue StandardError => e
puts "Unexpected error: #{e.class} - #{e.message}"
puts e.backtrace.first(5) if options[:debug]
return nil
end
end
nil
end
private
def create_request(method, uri, headers, body)
case method.to_s.upcase
when 'GET'
request = Net::HTTP::Get.new(uri)
when 'POST'
request = Net::HTTP::Post.new(uri)
when 'PUT'
request = Net::HTTP::Put.new(uri)
when 'DELETE'
request = Net::HTTP::Delete.new(uri)
when 'PATCH'
request = Net::HTTP::Patch.new(uri)
else
raise ArgumentError, "Unsupported HTTP method: #{method}"
end
# ヘッダー設定
headers.each { |key, value| request[key] = value }
# ボディ設定
if body
if headers['Content-Type'] == 'application/json'
request.body = body.is_a?(String) ? body : JSON.generate(body)
else
request.body = body
end
end
request
end
def parse_response(response, parse_json = true)
content_type = response.content_type
if parse_json && content_type&.include?('application/json')
begin
JSON.parse(response.body)
rescue JSON::ParserError => e
puts "JSON parse error: #{e.message}"
response.body
end
else
response.body
end
end
def handle_http_error(response)
case response.code.to_i
when 400
puts "Bad Request (400): リクエストが不正です"
when 401
puts "Unauthorized (401): 認証が必要です"
when 403
puts "Forbidden (403): アクセス権限がありません"
when 404
puts "Not Found (404): リソースが見つかりません"
when 409
puts "Conflict (409): リソースの競合が発生しました"
when 422
puts "Unprocessable Entity (422): バリデーションエラー"
puts response.body if response.body
when 429
puts "Too Many Requests (429): レート制限に達しました"
puts "Retry-After: #{response['Retry-After']}" if response['Retry-After']
when 500
puts "Internal Server Error (500): サーバー内部エラー"
when 502
puts "Bad Gateway (502): プロキシサーバーエラー"
when 503
puts "Service Unavailable (503): サービス利用不可"
when 504
puts "Gateway Timeout (504): ゲートウェイタイムアウト"
else
puts "HTTP Error #{response.code}: #{response.message}"
puts response.body if response.body
end
end
end
end
# レスポンス詳細分析クラス
class ResponseAnalyzer
def self.analyze(response)
puts "=== Response Analysis ==="
puts "Status: #{response.code} #{response.message}"
puts "HTTP Version: #{response.http_version}"
# ヘッダー分析
analyze_headers(response)
# ボディ分析
analyze_body(response)
# パフォーマンス分析
analyze_performance(response)
puts "========================"
end
private
def self.analyze_headers(response)
puts "\n--- Headers Analysis ---"
puts "Content-Type: #{response.content_type}"
puts "Content-Length: #{response.content_length}"
puts "Content-Encoding: #{response['Content-Encoding']}" if response['Content-Encoding']
puts "Cache-Control: #{response['Cache-Control']}" if response['Cache-Control']
puts "ETag: #{response['ETag']}" if response['ETag']
puts "Last-Modified: #{response['Last-Modified']}" if response['Last-Modified']
puts "Server: #{response['Server']}" if response['Server']
puts "Set-Cookie: #{response['Set-Cookie']}" if response['Set-Cookie']
end
def self.analyze_body(response)
puts "\n--- Body Analysis ---"
if response.body
puts "Body Size: #{response.body.bytesize} bytes"
puts "Body Encoding: #{response.body.encoding}"
# JSONか判定
if response.content_type&.include?('application/json')
begin
json_data = JSON.parse(response.body)
puts "JSON Structure: #{analyze_json_structure(json_data)}"
rescue JSON::ParserError
puts "Invalid JSON format"
end
end
else
puts "No body content"
end
end
def self.analyze_performance(response)
puts "\n--- Performance Info ---"
# Note: Net::HTTPでは詳細なタイミング情報は標準では取得不可
puts "Response Headers Count: #{response.to_hash.keys.length}"
puts "Keep-Alive: #{response['Connection']}" if response['Connection']
end
def self.analyze_json_structure(data, level = 0)
indent = " " * level
case data
when Hash
"Hash(#{data.keys.length} keys: #{data.keys.first(3).join(', ')}#{data.keys.length > 3 ? '...' : ''})"
when Array
"Array(#{data.length} items)"
else
data.class.name
end
end
end
# 実践的なAPIクライアント例
class RestAPIClient
def initialize(base_url, api_key = nil)
@base_url = base_url.chomp('/')
@api_key = api_key
end
def get(endpoint, params = {})
url = build_url(endpoint, params)
HTTPClient.safe_request(:get, url, {
headers: default_headers,
parse_json: true,
retries: 3,
timeout: 30
})
end
def post(endpoint, data = {})
url = build_url(endpoint)
HTTPClient.safe_request(:post, url, {
headers: default_headers.merge('Content-Type' => 'application/json'),
body: data,
parse_json: true,
retries: 2,
timeout: 45
})
end
def put(endpoint, data = {})
url = build_url(endpoint)
HTTPClient.safe_request(:put, url, {
headers: default_headers.merge('Content-Type' => 'application/json'),
body: data,
parse_json: true,
retries: 2,
timeout: 45
})
end
def delete(endpoint)
url = build_url(endpoint)
HTTPClient.safe_request(:delete, url, {
headers: default_headers,
parse_json: false,
retries: 2,
timeout: 30
})
end
private
def build_url(endpoint, params = {})
url = "#{@base_url}/#{endpoint.gsub(/^\//, '')}"
unless params.empty?
query_string = URI.encode_www_form(params)
url += "?#{query_string}"
end
url
end
def default_headers
headers = {
'User-Agent' => 'RestAPIClient/1.0 (Ruby Net::HTTP)',
'Accept' => 'application/json'
}
headers['Authorization'] = "Bearer #{@api_key}" if @api_key
headers
end
end
# 使用例
def error_handling_examples
# 基本的な使用例
result = HTTPClient.safe_request(:get, 'https://api.example.com/users', {
headers: { 'Authorization' => 'Bearer token123' },
parse_json: true,
retries: 3,
timeout: 30,
debug: true
})
puts "Result: #{result}"
# APIクライアントの使用例
client = RestAPIClient.new('https://api.example.com', 'your-api-key')
users = client.get('users', { page: 1, limit: 10 })
puts "Users: #{users}"
new_user = client.post('users', { name: '田中太郎', email: '[email protected]' })
puts "Created user: #{new_user}"
end
error_handling_examples
ファイルアップロード・ダウンロード・フォーム処理
require 'net/http'
require 'net/http/post/multipart' # gem install multipart-post
require 'uri'
require 'mime/types'
# ファイルアップロード(マルチパート形式)
def upload_file(file_path, upload_url, additional_fields = {})
uri = URI(upload_url)
# ファイルの存在確認
unless File.exist?(file_path)
puts "File not found: #{file_path}"
return nil
end
# MIMEタイプの検出
mime_type = MIME::Types.type_for(file_path).first&.content_type || 'application/octet-stream'
# マルチパートデータの準備
File.open(file_path, 'rb') do |file|
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.read_timeout = 300 # 5分のタイムアウト
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer your-upload-token'
# フォームデータの構築
form_data = additional_fields.merge(
'file' => UploadIO.new(file, mime_type, File.basename(file_path))
)
request.set_form(form_data, 'multipart/form-data')
begin
puts "Uploading file: #{file_path} (#{File.size(file_path)} bytes)"
response = http.request(request)
case response.code
when '200', '201'
puts "Upload successful: #{response.code}"
JSON.parse(response.body) if response.body
else
puts "Upload failed: #{response.code} - #{response.body}"
nil
end
rescue StandardError => e
puts "Upload error: #{e.message}"
nil
end
end
end
# 手動マルチパートフォーム(外部gemなしでの実装)
def upload_file_manual(file_path, upload_url, fields = {})
uri = URI(upload_url)
boundary = "----WebKitFormBoundary#{SecureRandom.hex(16)}"
File.open(file_path, 'rb') do |file|
# マルチパートボディの構築
body = []
# 追加フィールド
fields.each do |name, value|
body << "--#{boundary}\r\n"
body << "Content-Disposition: form-data; name=\"#{name}\"\r\n"
body << "\r\n"
body << "#{value}\r\n"
end
# ファイル部分
body << "--#{boundary}\r\n"
body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{File.basename(file_path)}\"\r\n"
body << "Content-Type: #{MIME::Types.type_for(file_path).first&.content_type || 'application/octet-stream'}\r\n"
body << "\r\n"
body << file.read
body << "\r\n"
body << "--#{boundary}--\r\n"
request_body = body.join
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
request['Content-Length'] = request_body.bytesize.to_s
request['Authorization'] = 'Bearer your-token'
request.body = request_body
response = http.request(request)
puts "Manual upload response: #{response.code}"
response
end
end
# ファイルダウンロード
def download_file(download_url, output_path, chunk_size = 8192)
uri = URI(download_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Get.new(uri)
request['User-Agent'] = 'Ruby FileDownloader/1.0'
begin
# ディレクトリの作成
FileUtils.mkdir_p(File.dirname(output_path))
http.request(request) do |response|
case response.code
when '200'
total_size = response['Content-Length']&.to_i
downloaded = 0
puts "Downloading: #{download_url}"
puts "Total size: #{total_size ? "#{total_size} bytes" : "unknown"}"
File.open(output_path, 'wb') do |file|
response.read_body do |chunk|
file.write(chunk)
downloaded += chunk.bytesize
# 進捗表示
if total_size
progress = (downloaded.to_f / total_size * 100).round(1)
print "\rProgress: #{progress}% (#{downloaded}/#{total_size} bytes)"
else
print "\rDownloaded: #{downloaded} bytes"
end
end
end
puts "\nDownload completed: #{output_path}"
return true
when '404'
puts "File not found: #{download_url}"
return false
else
puts "Download failed: #{response.code} - #{response.message}"
return false
end
end
rescue StandardError => e
puts "Download error: #{e.message}"
return false
end
end
# 大容量ファイルのストリーミングダウンロード
def stream_download(url, output_path)
uri = URI(url)
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
request = Net::HTTP::Get.new(uri)
http.request(request) do |response|
if response.code == '200'
File.open(output_path, 'wb') do |file|
response.read_body { |chunk| file.write(chunk) }
end
puts "Stream download completed: #{output_path}"
else
puts "Stream download failed: #{response.code}"
end
end
end
end
# フォームデータ処理
class FormProcessor
def self.submit_form(form_url, form_data, file_fields = {})
uri = URI(form_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Post.new(uri)
if file_fields.any?
# ファイル付きフォーム
submit_multipart_form(request, form_data, file_fields)
else
# 通常のフォーム
request.set_form_data(form_data)
end
response = http.request(request)
puts "Form submission response: #{response.code}"
response
end
def self.submit_json_form(form_url, json_data)
uri = URI(form_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = JSON.generate(json_data)
response = http.request(request)
puts "JSON form submission response: #{response.code}"
response
end
private
def self.submit_multipart_form(request, form_data, file_fields)
# multipart/form-data の実装
boundary = "----FormBoundary#{SecureRandom.hex(16)}"
body = []
# テキストフィールド
form_data.each do |name, value|
body << "--#{boundary}\r\n"
body << "Content-Disposition: form-data; name=\"#{name}\"\r\n"
body << "\r\n"
body << "#{value}\r\n"
end
# ファイルフィールド
file_fields.each do |name, file_path|
next unless File.exist?(file_path)
File.open(file_path, 'rb') do |file|
body << "--#{boundary}\r\n"
body << "Content-Disposition: form-data; name=\"#{name}\"; filename=\"#{File.basename(file_path)}\"\r\n"
body << "Content-Type: #{MIME::Types.type_for(file_path).first&.content_type || 'application/octet-stream'}\r\n"
body << "\r\n"
body << file.read
body << "\r\n"
end
end
body << "--#{boundary}--\r\n"
request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
request.body = body.join
end
end
# 使用例とテスト
def file_operations_examples
# ファイルアップロード例
upload_result = upload_file(
'/path/to/document.pdf',
'https://api.example.com/upload',
{
'category' => 'documents',
'public' => 'false',
'description' => 'テストドキュメント'
}
)
puts "Upload result: #{upload_result}"
# ファイルダウンロード例
download_success = download_file(
'https://api.example.com/files/sample.zip',
'/tmp/downloads/sample.zip'
)
puts "Download success: #{download_success}"
# フォーム送信例
form_response = FormProcessor.submit_form(
'https://example.com/contact',
{
'name' => '田中太郎',
'email' => '[email protected]',
'message' => 'お問い合わせ内容'
},
{
'attachment' => '/path/to/attachment.pdf'
}
)
puts "Form response: #{form_response.code}"
# JSON フォーム送信例
json_response = FormProcessor.submit_json_form(
'https://api.example.com/feedback',
{
user_id: 123,
rating: 5,
comment: 'とても良いサービスです',
timestamp: Time.now.iso8601
}
)
puts "JSON form response: #{json_response.code}"
end
file_operations_examples