続・玩式草子 ―戯れせんとや生まれけん―

第8回 ウィスキー・ボトル・ブルース(2番)

この記事を読むのに必要な時間:およそ 4 分

新元号「令和」が発表され,⁠平成」も残すところ一週間余りとなりました。筆者にとって平成の30年間は,社会人として働き出した時代であると共に,LinuxやOSSに出会って,それらと共に成長してきた時代だったように思います。

1991年,平成3年に最初のバージョンがリリースされたLinuxは,平成最後の年にメジャーバージョンが5.0にまで到達しました。Intel 80386CPUを積んだPC互換機の上でしか動かなかったLinuxが,平成の末にはスーパーコンピュータからIoT機器までサポートし,文字通りネット社会の基盤を支えるまでに成長しました。

もちろん「令和」の時代になってもLinuxの成長は続いていきます。⁠令和」の時代にLinuxがどう発展していくのか,Linusさんに代表されるカーネル開発者たちが,どのようなアイデアや機能をカーネルに持ち込むのか,興味が尽きることはありません。

さて,感慨に耽(ふけ)るのはこれくらいにしておいて,今回はBottleがブラウザ等のクライアントとデータをやりとりするあたりの話を扱います。

HTTPメソッドとルーティング

前回紹介したように,Bottleでは"@route"という指定(修飾)で,Pythonの関数とURIを結びつけます。

一方HTTPでは,クライアントがURIにアクセスする際の手段として,"GET"や"POST"といったメソッドを定めており,"GET"ならばサーバからデータを提供する,"POST"ならばサーバがデータを受け取って何らかの処理をする,等,サーバ側の動作を指定できるようになっています。

そのため,Bottleの"@route"の指定も,引数にHTTPの「メソッド」を指定して,⁠URI + メソッド」をPythonの関数に結びつけられるようになっており,1つのURIをGETメソッドでアクセスする場合とPOSTメソッドでアクセスする場合で異なる処理ができるように考慮されています。この機能を使えば,以下のようなスクリプトが書けます。

 1  #!/usr/bin/python
 2  
 3  from bottle import route,run,request
 4  
 5  @route('/login')
 6  def login():
 7      return '''
 8          <form action="/login" method="post">
 9              username: <input name="username" type="text" /> <br>
10              password: <input name="password" type="password" />
11              <input value="login" type="submit" />
12          </form>
13      '''
14  
15  @route('/login', method='POST')
16  def do_login():
17      username = request.forms.get('username')
18      password = request.forms.get('password')
19      return '''
20          username: {} <br>
21          password: {}
22      '''.format(username, password)
23  
24  run(host='localhost', port=8080, reloader=True, debug=True)

このスクリプトを実行し,ブラウザから"http://localhost:8080/login"にアクセスすると(GETメソッド)⁠5行目の"@route('/login')"で修飾した6-13行目までのlogin()関数が実行され,ブラウザにはユーザ名とパスワードの入力を促すフォーム画面が表示されます。

図1 GETメソッドでURIにアクセス

図1 GETメソッドでURIにアクセス

この画面を作っているのはPython特有の三連クォート(''')で囲まれた8~15行目までの<form>タグで,ページのソースを確認すると,この部分がそのまま送られていることがわかります。

図2 入力画面のソースコード

図2 入力画面のソースコード

画面に沿ってusernameとpasswordを入力し"login"ボタンを押すと,今度は<form>タグの指示により,"http://localhost:8080/login"をPOSTメソッドでアクセスします。リクエストを受け取ったBottleはHTTPのメソッドを見分けて,15行目の"@route('/login', method='POST')"で修飾したdo_login()関数を実行し,request.forms.get()メソッド経由で受け取ったusernameとpasswordを20,21行目の文字列に埋めこんで返します。

図3 POSTメソッドで送ったデータを表示

図3 POSTメソッドで送ったデータを表示

Bottleでは,上記例のようにmethod引数無しに"@route(...)"を使うと,HTTPで最もよく使われるGETメソッドと見做します。手元ではGETとPOSTしか試したことはないものの,BottleはGETPOSTPUTDELETEPATCHの各メソッドを見わけることができ,データのサマリのみを入手するHEADメソッドも,GETメソッドでコンテンツ本体を転送しないようにする形で対応しているそうです。

また,上記例では"@route(...)"修飾子のmethod引数としてメソッドを指定しましたが,

  from bottle import get, post

としてgetやpostモジュールをインポートしておけば,"@route('/login', method='POST')"の代わりに

  @get('/login')
  def login:
  ....

  @post('/login')
  def do_login:
  ....

のようにメソッドで修飾したルーティングを書くことも可能で,こちらの方が読み易いかもしれません。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたものの,いつの間にかミイラ取りがミイラになってOSSの世界にどっぷりと漬かってしまいました。最近は田舎に隠棲して半農半自営な生活をしながらソフトウェアと戯れています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html