หากคุณอยากได้ข้อมูลจากเว็บไซต์ หรือ submit forms, upload files ฯลฯ
คุณต้องส่ง HTTP request และ process response
ในบทความนี้คุณจะเรียนรู้:
- ส่ง HTTP request ง่ายๆ ด้วย net/http
- ส่ง SSL requests
- Submit data ด้วย POST request
- ส่ง custom headers
- เลือก HTTP client ที่ดีที่สุดสำหรับสถานการณ์
มาเริ่มกัน!
วิธีส่ง HTTP Request
Ruby มาพร้อม built-in http client เรียกว่า net/http ใช้ส่ง request ทุกประเภท
net/http example:
require 'net/http'
Net::HTTP.get('example.com', '/index.html')
จะคืน string พร้อม HTML content ของเพจ
แตบ่อยครั้งอยากได้มากกว่า HTML content
เช่น HTTP response status
โดยไม่มี response status คุณไม่รู้ว่า request สำเร็จหรือ fail
วิธีได้ status:
response = Net::HTTP.get_response('example.com', '/')
response.code # 200
ตอนนี้อยากได้ response content เรียกเมธอด body:
response.body
วิธีใช้ HTTParty Gem
มี gems หลายตัวทำให้ง่ายขึ้น
หนึ่งคือ httparty
วิธีใช้:
require 'httparty'
response = HTTParty.get('https://example.com')
response.code # 200
response.body # ...
ประโยชน์ของ HTTP gem:
- ใช้ง่ายกว่า
- ไม่มี
get_responseแยกgetให้ response object แล้ว - ทำ SSL requests ให้ transparent (ดู next section)
ส่ง SSL Requests
หากลองส่ง SSL request ด้วย net/http:
Net::HTTP.get_response("example.com", "/", 443)
ได้:
Errno::ECONNRESET: Connection reset by peer
ต้องทำแบบนี้:
net = Net::HTTP.new("example.com", 443)
net.use_ssl = true
net.get_response("/")
ประหยัดงาน ใช้ gem 🙂
วิธี Submit Data ด้วย Post Request
GET request ใช้ request information
เช่น download image, css, javascript…
แต่หากอยาก submit information ใช้ POST request
ตัวอย่าง:
HTTParty.post("https://example.com/login", body: { user: "test@example.com", password: "chunky_bacon" })
Upload file ต้อง multipart request ซึ่ง HTTParty ไม่ support
ใช้ rest-client gem:
require 'rest-client'
RestClient.post '/profile', file: File.new('photo.jpg', 'rb')
หรือ Faraday gem:
require 'faraday'
conn = Faraday.new do |f|
f.request :multipart
f.request :url_encoded
f.adapter :net_http
end
file_io = Faraday::UploadIO.new('photo.jpg', 'image/jpeg')
conn.post('https://example.com/profile', file: file_io)
วิธีส่ง Custom HTTP Headers
คุณส่ง custom headers กับ HTTP request ได้
ช่วย ส่งข้อมูลเพิ่มกับ request รวมถึง:
- Cookies
- User-agent
- Caching preferences
- Content-type
- Accept (เพื่อรับ JSON กลับ หรืออย่างอื่น)
วิธีทำ:
Faraday.new('https://example.com', headers: { 'User-Agent' => 'test' }).get
ผมสร้าง Faraday object (ด้วย new) แล้วเรียก get
หรือทำแบบนี้:
Faraday.post(
"https://example.com/login/oauth/access_token",
URI.encode_www_form(
code: params[:code],
client_id: ENV["example_client_id"],
client_secret: ENV["example_client_secret"],
),
{ "Content-Type" => "application/x-www-form-urlencoded",
"Accept" => "application/json" }
)
ทำงานดีสำหรับ OAuth type requests
เลือก Ruby HTTP Client ที่ดีที่สุด
มี HTTP clients หลายตัวใน Ruby
แตควรเลือกตัวไหน?
ช่วยตัดสินใจ ผมเตรียมตารางเปรียบเทียบ
นี่คือ:
| REPO | STARS | RECENT_COMMIT_COUNT | LAST_COMMIT | LATEST_RELEASE | CREATED_DATE |
|---|---|---|---|---|---|
| lostisland/faraday | 4817 | 26 | 2020-07-09 09:43:09 | 2020-03-29 13:46:47 | 2009-12-10 17:14:55 |
| rest-client/rest-client | 4913 | 0 | 2019-08-25 21:41:17 | 2019-08-21 22:50:21 | 2009-12-07 19:34:29 |
| typhoeus/typhoeus | 3739 | 2 | 2020-05-17 19:33:54 | 2020-01-15 16:24:17 | 2009-02-18 23:14:50 |
| jnunemaker/httparty | 5220 | 11 | 2020-06-10 18:40:13 | 2020-06-10 18:40:13 | 2008-07-28 20:55:11 |
| excon/excon | 1018 | 14 | 2020-06-30 11:30:12 | 2020-06-17 12:07:02 | 2009-10-25 17:50:46 |
| httprb/http | 2623 | 13 | 2020-03-30 12:34:38 | 2020-02-26 17:33:37 | 2011-10-06 04:19:10 |
ดู popularity และ maintenance เป็นขั้นแรกดีในการ evaluate options
แตความแตกต่างทาง technical คืออะไร?
Gems หลายตัวเป็น wrappers รอบ net/http library:
- excon
- httparty
- rest client
ในขณะที่ Faraday เป็น adapter gem ใช้ implementations ต่างๆ ได้
และ Typhoeus เป็น wrapper รอบ C libcurl library
Typhoeus สำหรับ Multi-Threading
Typhoeus รองรับ concurrent requests โดยไม่ต้องเขียน concurrent code
ทำให้ Typhoeus เป็นตัวเลือกดีที่สุดหากอยาก maximize requests per second
ใช้ Typhoeus กับ multi-threading:
require 'typhoeus'
hydra = Typhoeus::Hydra.hydra
request = Typhoeus::Request.new("https://www.rubyguides.com")
hydra.queue(request)
hydra.queue(request)
hydra.run
Faraday Gem สำหรับ Adaptability
Faraday เลือก implementation ใดก็ได้จาก net/http, Typhoeus, หรือ rest-client ทั้งหมดจาก interface เดียว
Default เป็น net/http แตเปลี่ยนได้:
Faraday.default_adapter = :typhoeus
สิ่งน่าสนใจอีกอย่าง Faraday รองรับ middleware
Middleware เหมือน plugin ช่วย modify request หรือ response อย่างเฉพาะเจาะจง
ตัวอย่าง:
require 'faraday_middleware'
client = Faraday.new do |f|
f.response :json
f.adapter :net_http
end
client.get('https://api.github.com/repos/vmg/redcarpet/issues')
Middleware นี้ parse response เป็น JSON อัตโนมัติ
หากอยากส่ง JSON แทน parse ใช้ f.request :json แทน f.response :json
Faraday Video
Bonus: วิธี Debug HTTP Requests
หากอยากเห็นว่าคุณส่งอะไรจริงๆ เพื่อแน่ใจว่าทำงานถูกต้อง…
…มี trick สำหรับคุณ
ใช้ one-liner นี้:
ruby -rsocket -e "trap('SIGINT') { exit }; Socket.tcp_server_loop(8080) { |s,_| puts s.readpartial(1024); puts; s.puts 'HTTP/1.1 200'; s.close }
สร้าง server port 8080 พิมพ์ทุกอย่างที่รับ คืน HTTP status แล้ว close connection
ส่ง requests ต่อ localhost:8080 เพื่อดู
แบบนี้:
Faraday.new('https://localhost:8080', headers: { 'User-Agent' => 'test', 'foo' => '1234' }).get
# GET / HTTP/1.1
# User-Agent: test
# Foo: 1234
# Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
# Accept: */*
# Connection: close
# Host: localhost:8080
ตัวเลือกอื่นรวม gem httplog หรือ tool mitmproxy
สรุป
คุณเรียนรู้ส่ง HTTP requests ทุกแบบ เริ่มจาก GET request information ถึง POST submit information
คุณเห็น overview ของ popular Ruby gems สำหรับ HTTP requests ผมชอบ faraday เพราะ flexibility แตเลือก gem อื่นได้หากเหมาะกว่า
หากเพลิดเพลินโพสต์นี้แชร์ให้เพื่อนเพื่อให้พวกเขาเพลิดเพลิน 🙂
ขอบคุณที่อ่าน!