Next Previous Contents

2. CGI

Det å skrive CGI-skript (Common Gateway Interface) i Ruby skiller seg ikke nevneverdig fra å skrive CGI-skript i andre språk. Skriv ut HTTP-hodelinjer (headers), hent inn CGI-variabler, generer HTML (eller noe annet interessant innhold) dynamisk og spyl det av gårde til klienten.

  1| #!/store/bin/ruby
  2| # ^^^ - linje for å angi hvor man finner Ruby-fortolkeren
  3| 
  4| # Print ut HTTP-hodelinjer for å angi at vi serverer HTML.
  5| print "Content-type: text/html\r\n\r\n"
  6| 
  7| # Server litt HTML.
  8| print "<html><body><h1>Hei verden!</h1></body></html>"

Øverste linje angir hvor Ruby-fortolkeren befinner seg på serveren. /store/bin/ruby er bare en vanlig plassering på NTNU maskiner som bruker store. Prøv å skriv 'which ruby' om du lurer på hvor fortolkeren er på den maskinen du er på nå.

Men dette var ikke særlig spennende uten noen mulighet for å påvirke resultatet dynamisk...

2.1 Variabler

... så la oss lage en liten web-basert kalkulator.

  1| #!/store/bin/ruby
  2| print "Content-type: text/html\r\n\r\n"
  3| # Starter HTML-dokumentet.
  4| print '<html><body>'
  5| 
  6| # Hent inn CGI-biblioteket.
  7| require 'cgi'
  8| # Lag en instans slik at vi får tak i CGI-variablene.
  9| cgi = CGI.new
 10| 
 11| # Hent CGI-variablene
 12| x = cgi['x'][0] # Oppslaget returnerer en Array,
 13| y = cgi['y'][0] # så vi plukker ut første element.
 14| 
 15| # Skriv dem bare ut dersom vi fikk noe.
 16| if (x and x.size.nonzero?) and
 17|    (y and y.size.nonzero?) then
 18|   a = x.to_i # Gjør om til heltall.
 19|   b = y.to_i
 20|   print "#{a} multiplisert med #{b} er ", a*b
 21| end
 22| 
 23| # Skriv ut et lite skjema.
 24| print '<form>'
 25| print '<input name="x" type="text"> *'
 26| print '<input name="y" type="text"> = '
 27| print '<input type="submit" value="gange">'
 28| print '</form>'
 29| 
 30| # Avslutter HTML-dokumentet.
 31| print '</body></html>'

2.2 HTML

CGI-biblioteket kan også hjelpe deg litt med å skrive HTML-koden.

  1| #!/store/bin/ruby
  2| require 'cgi'
  3| 
  4| # CGI-biblioteket kan også hjelpe deg med å få skrevet HTML-koden.
  5| cgi = CGI.new('html4')
  6| cgi.out {
  7|   cgi.html {
  8|     cgi.head { 
  9|       cgi.title { 'Penere kildekode?' } 
 10|     } + 
 11|     cgi.body {
 12|       cgi.h1 { 'Gjør dette kildekoden penere?' } + 
 13|       cgi.p +
 14|       'Eller får man krøllparentes-overdose?'
 15|     }
 16|   }
 17| }

Du slipper å huske hvilke element som skal avsluttes og i hvilken rekkefølge, men får noe som ligner litt for mye på Lisp.

2.3 Cookies

Cookies er en måte å lagre små datamengder på maskinen til brukeren som surfer inn på sidene våre, som vi kan hente ut igjen når de kommer tilbake en annen gang.

  1| #!/store/bin/ruby
  2| require 'cgi'
  3| c = CGI.new('html4')
  4| 
  5| # Hent ut den gamle kaken.
  6| gammel_cookie = c.cookies['rubywebnuby']
  7| 
  8| # Kurstekst i første element, antall besøk i andre element.
  9| kurs_tekst, antall_tekst = gammel_cookie
 10| antall_besok = if antall_tekst then 
 11|                  antall_tekst.to_i + 1 
 12|                else 0 end
 13| 
 14| # Lag ny kake.
 15| ny_cookie = CGI::Cookie.new('rubywebnuby',    # Kakenavn.
 16|   'Ruby Web Nuby', antall_besok.to_s          # Verdier.
 17| )
 18| 
 19| c.out( 'cookie' => [ny_cookie] ) do # Sett kaken via HTTP. 
 20|   c.html do 
 21|     c.body do
 22|       # Print ut de forrige kakene
 23|       gammel_cookie.join(c.br) + 
 24|         "<P>Du har vært her #{antall_besok} ganger før, " +
 25|         "da i forbindelse med #{kurs_tekst} kurs."
 26|     end 
 27|   end 
 28| end

Cookies er et kjekt verktøy når man ikke har noen database å lagre i, dataene er små eller brukerne er overmåte allergisk mot innloggingsskjermer. Ellers er det kanskje en ide å lagre ting på serversiden og/eller i skjulte input-elementer.

2.4 Sesjoner

Sesjoner er et overbygg over cookies, som lagrer en liten bit data i en cookie hos klienten, og (potensielt) et tonn med data på serveren.

  1| #!/store/bin/ruby
  2| require 'cgi'
  3| require 'cgi/session'
  4| c = CGI.new('html4')
  5| sesjon = CGI::Session.new( c, 
  6|   'session_key' => 'rubywebnuby2',
  7|   'prefix' => 'ruby_sesjon.')
  8| 
  9| # Hent ut antall besøk fra sesjonen
 10| antall_tekst = sesjon['AntallBesok']
 11| antall_besok = (antall_tekst ? antall_tekst.to_i+1 : 0)
 12| 
 13| # Sett det nye antallet tilbake i sesjonen
 14| sesjon['AntallBesok'] = antall_besok
 15| 
 16| c.out do 
 17|   c.html do 
 18|     c.body do
 19|      "Du har vært her #{sesjon['AntallBesok']} ganger før."
 20|     end 
 21|   end 
 22| end

Da har vi iallfall fått lagret en god del mer på serversiden, og høyde, alder, øyenfarge, samt en million "theme"-innstillinger for webapplikasjonen vår må ikke sendes over nettet hver gang en side hentes.

2.5 Ytelse

Til nå har vi bare kjørt disse CGI-skriptene på den trauste, trege måten. For hvert kall til sidene, må Ruby-fortolkeren startes opp og biblioteker lastes. Dette er ufattelig ineffektivt.

Vi trenger å ha minimum Ruby-fortolkeren, og helst også biblioteker, ferdig lastet og klare til dyst når en HTTP-forespørsel kommer inn. Det er flere muligheter, blant annet:

mod_ruby, WEBrick, Radical, fastcgi, IOWA, Borges, httpd, httpserv, wwwd, wwwsrv ... etc


Next Previous Contents