Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ HTTP Requests ใน Ruby: คู่มือสมบูรณ์

หากคุณอยากได้ข้อมูลจากเว็บไซต์ หรือ 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 อื่นได้หากเหมาะกว่า

หากเพลิดเพลินโพสต์นี้แชร์ให้เพื่อนเพื่อให้พวกเขาเพลิดเพลิน 🙂

ขอบคุณที่อ่าน!