Nếu muốn lấy thông tin từ website, hoặc submit form, upload file, v.v.
Bạn cần gửi HTTP request và xử lý response.
Bài này bạn học cách:
- Làm HTTP request đơn giản với net/http
- Gửi SSL request
- Submit data với POST request
- Gửi custom header
- Chọn HTTP client tốt nhất cho tình huống
Làm nào!
Cách gửi HTTP Request
Ruby có built-in http client, gọi là net/http, dùng gửi bất kỳ request nào.
Ví dụ net/http:
require 'net/http'
Net::HTTP.get('example.com', '/index.html')
Này trả string HTML content trang.
Thường bạn muốn hơn HTML content.
Như HTTP response status.
Không có status bạn không biết request thành công hay fail.
Cách lấy status:
response = Net::HTTP.get_response('example.com', '/')
response.code # 200
Nếu muốn response content gọi method body:
response.body
Cách dùng Gem HTTParty
Nhiều gem làm dễ cho bạn.
Một gem là httparty.
Cách dùng:
require 'httparty'
response = HTTParty.get('https://example.com')
response.code # 200
response.body # ...
Lợi ích dùng HTTP gem:
- Dễ dùng hơn.
- Không có
get_responseriêng,getđã cho response object. - Như bạn thấy sau, họ làm SSL request transparent
Gửi SSL Request
Nếu thử gửi SSL request với net/http:
Net::HTTP.get_response("example.com", "/", 443)
Bạn nhận:
Errno::ECONNRESET: Connection reset by peer
Phải làm thế này:
net = Net::HTTP.new("example.com", 443)
net.use_ssl = true
net.get_response("/")
Tiết kiệm công sức, dùng gem 🙂
Cách Submit Data với Post Request
GET request dùng yêu cầu thông tin.
Như download ảnh, css, javascript…
Nhưng nếu muốn gửi thông tin dùng POST request.
Ví dụ:
HTTParty.post("https://example.com/login", body: { user: "test@example.com", password: "chunky_bacon" })
Upload file cần multipart request, không supported bởi HTTParty.
Dùng rest-client gem:
require 'rest-client'
RestClient.post '/profile', file: File.new('photo.jpg', 'rb')
Hoặc 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)
Cách gửi Custom HTTP Headers
Bạn gửi custom header với HTTP request.
Giúp gửi thêm data với request, bao gồm:
- Cookies
- User-agent
- Caching preferences
- Content-type
- Accept (để nhận JSON, hoặc khác)
Cách làm:
Faraday.new('https://example.com', headers: { 'User-Agent' => 'test' }).get
Tôi tạo Faraday object (dùng new), rồi gọi get.
Hoặc làm kiểu này:
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" }
)
Này chạy tốt cho OAuth request.
Chọn Best Ruby HTTP Client
Nhiều HTTP client Ruby.
Nên chọn cái nào?
Để giúp decide tôi chuẩn bị bảng so sánh.
Đây:
| 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 |
Xem popularity và maintenance là bước đầu evaluate option.
Nhưng khác biệt kỹ thuật là gì?
Nhiều gem là wrapper quanh net/http:
- excon
- httparty
- rest client
Trong khi Faraday là adapter gem, dùng implementation khác nhau.
Và Typhoeus wrapper C libcurl library.
Typhoeus cho Multi-Threading
Typhoeus hỗ trợ concurrent request không viết concurrent code.
Làm Typhoeus best choice nếu maximize requests/second.
Dùng 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 cho Adaptability
Faraday cho phép chọn implementation từ net/http, Typhoeus, rest-client từ cùng interface.
Mặc định net/http, đổi như sau:
Faraday.default_adapter = :typhoeus
Điều thú vị khác: Faraday hỗ trợ middleware.
Middleware như plugin modify request/response cách cụ thể.
Ví dụ:
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 này parse response JSON tự động.
Nếu muốn gửi JSON thay vì parse, dùng f.request :json thay f.response :json.
Faraday Video
Bonus: Cách Debug HTTP Request
Nếu muốn xem chính xác code gửi gì để chắc chắn chạy đúng…
…thì tôi có trick nhỏ.
Bạn dùng 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 }
Này tạo server port 8080 in mọi thứ nhận, trả HTTP status và close connection.
Bạn gửi request対 localhost:8080 xem chúng.
Như sau:
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
Option khác: gem httplog, hoặc tool mitmproxy.
Tóm tắt
Bạn học gửi mọi loại HTTP request, từ GET cơ bản lấy thông tin, đến POST submit thông tin.
Bạn xem overview gem Ruby phổ biến cho HTTP. Favorite của tôi faraday vì flexibility, nhưng chọn gem khác nếu fit needs hơn.
Nếu thích post hãy chia sẻ bạn bè để họ tận hưởng 🙂
Cảm ơn đã đọc!