Net:HTTP
HTTP je internetový protokol určený pre výmenu hypertextových dokumentov vo formáte HTML. Net:HTTP je štandardný Ruby modul pre vytváranie HTTP klientov pomocou ktorých posielame HTTP požiadavky a prijímame HTTP odpovede. Ruby má vo svojom obsiahlom balíčkovom systéme viaceré ďalšie knižnice pre prácu s HTTP, napríklad Faraday, HTTPClient, alebo rest-client.
Sinatra
Sinatra je populárny webový aplikačný framework určený pre jazyk Ruby. Jeho popularita pramení hlavne z jednoduchosti, s akou si môžeme vytvárať menšie webové aplikácie. Sinatra je alternatívou k Ruby on Rails, ktorý je v súčasnosti najpopulárnejší Ruby framework; má však oveľa strmšiu krivku učenia. Sinatra má domovskú stránku na www.sinatrarb.com.
Niektorí z našich klientov sa budú napájať na Sinatra aplikácie.
$ sudo gem install sinatra $ sudo gem install thin
Pomocou týchto príkazov si nainštalujeme Sinatru a webový server Thin. Ak je Thin nainštalovaný, Sinatra si ho automaticky zvolí namiesto zabudovaného serveru WEBrick.
Vytvorme si projektový adresár a v ňom nasledujúci main.rb
súbor:
require 'sinatra' get '/' do "First application" end
V tejto jednoduchej Sinatra aplikácii reagujeme na prístup k ceste /
. Aplikácia vracia krátku správu klientovi.
$ ruby main.rb == Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from Thin Thin web server (v1.6.4 codename Gob Bluth) Maximum connections set to 1024 Listening on localhost:4567, CTRL+C to stop
Aplikáciu štartujeme príkazom ruby main.rb
. Spustí sa Thin server, ktorý načúva na porte 4567.
$ curl localhost:4567/ First application
Pomocou utility curl
sa pripojíme na server a na cestu /
. Na termináli sa nám zobrazí správa.
V príkladoch, kde budeme mať Sinatra aplikáciu, si vždy najprv spustíme Sinatru pomocou $ ruby main.rb
v jednom termináli a v inom spustíme Ruby HTTP klienta, ktorý sa bude pripájať a aplikácii; napríklad: $ ./get_content.rb
.
Stiahnutie obsahu stránky
Metóda get_print
je vysokoúrovňovou metódou na stiahnutie obsahu dokumentu. Metóda zároveň zobrazí stiahnutý obsah na termináli.
#!/usr/bin/ruby require 'net/http' uri = URI 'http://www.something.com/' Net::HTTP.get_print uri
Skript stiahne obsah stránky www.something.com
. Modul net/http
úzko spolupracuje s modulom uri
.
require 'net/http'
Tento príkaz nám dáva prístup k obom modulom: net/http
a uri
; takže nemusíme použiť príkaz zvlášť aj pre uri
.
$ ./get_content.rb <html><head><title>Something.</title></head> <body>Something.</body> </html>
Toto je výstup programu get_content.rb
.
Nasledujúci program stiahne webový dokument a odstráni z neho HTML značky.
#!/usr/bin/ruby require 'net/http' uri = URI "http://www.something.com/" doc = Net::HTTP.get uri puts doc.gsub %r{</?[^>]+?>}, ''
Tento skript využíva metódu get
na stiahnutie obsahu stránky www.something.com
a odstráni z neho HTML značky.
puts doc.gsub %r{</?[^>]+?>}, ''
Na odstránenie HTML značiek využijeme regulárny výraz.
$ ./strip_tags.rb Something. Something.
Skript zobrazí titulok a obsah stránky.
Status
Metódy code
a message
nám udávajú status HTTP odpovede.
#!/usr/bin/ruby require 'net/http' uri = URI 'http://www.something.com' res = Net::HTTP.get_response uri puts res.message puts res.code uri = URI 'http://www.something.com/news/' res = Net::HTTP.get_response uri puts res.message puts res.code uri = URI 'http://www.urbandicionary.com/define.php?term=Dog' res = Net::HTTP.get_response uri puts res.message puts res.code
V tomto programe pošleme tri rôzne HTTP požiadavky pomocou metódy get_response
a zistíme status HTTP odpovedí.
uri = URI 'http://www.something.com/news/' res = Net::HTTP.get_response uri puts res.message puts res.code
Status HTTP odpovede získame pomocou metód message
a code
. Keďže daný zdroj nie je platný, dostaneme ako odpoveď kód 404, Not Found.
$ ./status.rb OK 200 Not Found 404 Found 302
200 je kód pre úspešnú HTTP požiadavku, 404 nám hovorí, že daný zdroj nebolo možné nájsť a 302 znamená, že zdroj bol dočasne premiestnený.
Metóda head
Metóda head
slúži na získanie hlavičky dokumentu. Hlavička obsahuje rôzne polia opisujúce dokument, napríklad názov obsluhujúceho servera, typ a veľkosť dokumentu, alebo čas poslednej modifikácie dokumentu. Týmto informáciám sa hovorí metadáta.
#!/usr/bin/ruby require 'net/http' uri = URI "http://www.something.com" http = Net::HTTP.new uri.host, uri.port res = http.head '/' puts res['server'] puts res['date'] puts res['last-modified'] puts res['content-type'] puts res['content-length']
Program stiahne HTML dokument z adresy www.something.com
a vypíše názov servera, dátum HTTP odpovede, čas poslednej modifikácie dokumentu, typ dokumentu a jeho veľkosť.
$ ./head.rb Apache/2.4.12 (FreeBSD) OpenSSL/1.0.1l-freebsd mod_fastcgi/mod_fastcgi-SNAP-0910052141 Wed, 11 May 2016 19:30:56 GMT Mon, 25 Oct 1999 15:36:02 GMT text/html 77
Z výstupu vidíme, že webové stránky manažuje server Apache na operačnom systéme FreeBSD. Dokument bol naposledy modifikovaný v roku 1999. Stiahnutým obsahom je HTML dokument, ktorý má veľkosť 77 bajtov.
Metóda get
Metóda get
vykoná požiadavku GET smerom k serveru. GET žiada server o špecifický zdroj.
require 'sinatra' get '/greet' do "Hello #{params[:name]}" end
Toto je súbor aplikácie Sinatra. Keď zachytíme prístup k ceste /greet
, vrátime správu, ktorá bude obsahovať meno zaslané klientom.
#!/usr/bin/ruby require 'net/http' uri = URI "http://localhost:4567/greet" params = { :name => 'Peter' } uri.query = URI.encode_www_form params puts Net::HTTP.get uri
Tento skript pošle premennú s hodnotou našej Sinatra aplikácii. Premenná je zakódovaná do URL identifikátora.
params = { :name => 'Peter' }
Toto je parameter, ktorý zašleme serveru.
uri.query = URI.encode_www_form params
Parameter zakódujeme do identifikátora zdroja pomocou metódy encode_www_form
method.
puts Net::HTTP.get uri
Pomocou metódy get
pošleme GET požiadavku serveru. Server nám vráti odpoveď, ktorú vypíšeme na terminál.
$ ./mget.rb Hello Peter
Toto je výstup programu.
127.0.0.1 - - [11/May/2016:21:51:12 +0200] "GET /greet?name=Peter HTTP/1.1" 200 11 0.0280
V tomto logu servera Thin môžeme vidieť, že parameter bol zakódovaný do URL identifikátora.
User agent
User-Agent je pole hlavičky HTTP požiadavky, ktorou sa identifikuje klient. V ďalšom príklade si ukážeme, ako si nastaviť názov vlastného agenta v požiadavke, ktorú pošleme Sinatra aplikácii.
require 'sinatra' get '/agent' do request.user_agent end
Táto Sinatra aplikácia zistí názov klienta, ktorý vykonal HTTP požiadavku a pošle ho späť klientovi.
#!/usr/bin/ruby require 'net/http' uri = URI "http://localhost:4567" http = Net::HTTP.new uri.host, uri.port res = http.get '/agent', {'User-Agent' => 'Ruby script'} puts res.body
Tento skript pošle GET požiadavku, v hlavičke ktorej sa nachádza nami nastavené pole User-Agent
.
res = http.get '/agent', {'User-Agent' => 'Ruby script'}
Voľbu User-Agent
sme pridali ako druhý parameter metóde get
.
$ ./agent.rb Ruby script
Server odpovedal názvom nášho klienta, ktorý sme mu zaslali v požiadavke.
Metóda post
Metódou post
zašleme požiadavku POST na uvedený URL zdroj. Zasielané dáta nie sú pridané do URL.
require 'sinatra' post '/target' do "Hello #{params[:name]}" end
Táto Sinatra aplikácia vracia správu v prípade prístupu na cestu /target
. Spracuje dáta poslané POST metódou a zahrnie ich do správy klientovi.
#!/usr/bin/ruby require 'net/http' uri = URI "http://localhost:4567/target" params = { :name => 'Peter' } res = Net::HTTP.post_form uri, params puts res.body
Tento skript vygeneruje POST požiadavku s premennou name
, ktorá má hodnotu Peter
. POST požiadavku zabezpečí metóda Net::HTTP.post_form
.
$ ./mpost.rb Hello Peter
Toto je výstup skriptu mpost.rb
.
127.0.0.1 - - [12/May/2016:11:36:16 +0200] "POST /target HTTP/1.1" 200 11 0.0006
Z logu web servera vidíme, že požiadavka POST nepridáva posielané dáta do URL zdroja.
Stiahnutie definícií z online slovníka
V ďalšom príklade si vyhľadáme definíciu slova zo stránky www.dictionary.com. Na parsovanie HTML kódu použijeme modul nokogiri
. Nokogiri je najobľúbenejší Ruby HTML, XML, SAX a Reader parser. Modul sa nainštaluje príkazom sudo gem install nokogiri
.
#!/usr/bin/ruby require 'net/http' require 'nokogiri' term = 'cat' uri = URI 'http://www.dictionary.com/browse/'+term res = Net::HTTP.get uri doc = Nokogiri::HTML res doc.css("div.def-content").map do |node| s = node.text.strip! s.gsub!(/\s{3,}/, " ") unless (s == nil) puts s unless (s == nil) end
Pomocou tohto skriptu nájdeme definície slova ‚cat‘ zo stránky www.dictionary.com
.
uri = URI 'http://www.dictionary.com/browse/'+term
Zvolený termín pridáme na koniec URL zdroja.
res = Net::HTTP.get uri
Pomocou get
metódy získame odpoveď servera, v ktorej sa nachádzajú naše definície.
doc = Nokogiri::HTML res doc.css("div.def-content").map do |node| s = node.text.strip! s.gsub!(/\s{3,}/, " ") unless (s == nil) puts s unless (s == nil) end
Definície sa nachádzajú v značke <div class="def-content">
. Zlepšíme formátovanie výstupu tým, že odstránime nadmerné biele znaky.
$ ./get_term.rb a small domesticated carnivore, Felis domestica or F. catus, bred in a number of varieties. any of several carnivores of the family Felidae, as the lion, tiger, leopard or jaguar, etc. Slang. a person, especially a man. a devotee of jazz. a woman given to spiteful or malicious gossip. the fur of the domestic cat. ...
Toto je skrátený výstup programu.
JSON
JSON (JavaScript Object Notation) je odľahčený formát na výmenu dát. Pre ľudí je čitateľný a pre programy ľahko generovateľný a analyzovateľný.
$ sudo gem install json
Potrebujeme naištalovať modul json
.
require 'sinatra' require 'json' get '/example.json' do content_type :json { :name => 'Jane', :age => 17 }.to_json end
Sinatra aplikácia vracia dáta vo formáte JSON. Na ich generovanie využije metódu to_json
.
#!/usr/bin/ruby require 'net/http' require 'json' uri = URI 'http://localhost:4567/example.json' res = Net::HTTP.get uri data = JSON.parse res puts data["name"] puts data["age"]
Tento skript číta JSON dáta zaslané Sinatra aplikáciou. Na spracovanie JSON dát sa použije metóda JSON.parse
.
$ ./parse_json.rb Jane 17
Toto je výstup programu parse_json.rb
.
Ďalej pošleme JSON dáta Ruby programom Sinatra aplikácii.
require 'sinatra' require 'json' post '/readjson' do data = JSON.parse request.body.read "#{data["name"]} is #{data["age"]} years old" end
Aplikácia spracuje prijaté JSON dáta a zašle ich späť klientovi v textovej správe.
#!/usr/bin/ruby require 'net/http' require 'json' uri = URI 'http://localhost:4567/readjson' req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'} req.body = {:name => 'Jane', :age => 17}.to_json res = Net::HTTP.start(uri.hostname, uri.port) do |http| http.request req end puts res.body
Tento skript pošle JSON dáta Sinatra aplikácii a zobrazí jej odpoveď.
req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'}
V hlavičke HTTP požiadavky musíme uviesť typ obsahu 'application/json'
.
$ ./post_json.rb Jane is 17 years old
Toto je výstup príkladu.
Autentifikácia
Modul net/http
obsahuje metódu basic_auth
na vykonanie základnej HTTP autentifikácie.
$ sudo gem install sinatra-basic-auth
Pre Sinatru nainštalujeme modul sinatra-basic-auth
.
require 'sinatra' require "sinatra/basic_auth" authorize do |username, password| username == "user7" && password == "7user" end get '/' do "hello" end protect do get "/secure" do "This is restricted area" end end
V Sinatra aplikácii vykonáme autorizáciu a špecifikujeme cestu, ktorá bude vyžadovať autentifikáciu; v našom prípade: /secure
.
#!/usr/bin/ruby require 'net/http' uri = URI 'http://localhost:4567/secure' req = Net::HTTP::Get.new uri.path req.basic_auth 'user7', '7user' res = Net::HTTP.start uri.hostname, uri.port do |http| http.request req end puts res.body
Skript sa pokúsi o prístup k zabezpečenému zdroju.
req = Net::HTTP::Get.new uri.path req.basic_auth 'user7', '7user'
Pomocou metódy basic_auth
uvedieme meno a heslo používateľa.
$ ./credentials.rb This is restricted area
Prístup k zabezpečenému zdroju sa nám podaril.
Zdroje
- API rozhranie modulu Net::HTTP
- Dokumentácia k Sinatre
V tomto článku sme si uviedli základné postupy pre prácu s Ruby modulom Net::HTTP. Aplikácie na strane servera sme si vytvorili pomocou Ruby frameworku Sinatra. V angličtine vyšiel tento článok na autorovej webovej stránke.