Symfoware

Symfowareについての考察blog

Python 組み込みのCGIHTTPServerやhttp.serverでcgiを動かす

javascriptライブラリの使い方を調べている時、ローカルに簡単なwebサーバーが欲しくなる時があります。

普段はPythonの組み込みモジュールSimpleHTTPServerを使用し
htmlファイルを保存したディレクトリで


$ python -m SimpleHTTPServer



Python 3の場合は


$ python3 -m http.server



でwebサーバーを起動。
ブラウザでhttp://localhost:8000を表示し、動作を確認していました。

ajax通信を扱うライブラリの場合は、送信したパラメーターに応じて
異なる応答を返してほしい。

簡単なcgiプログラムでアプリケーション側を代用できないか調べてみます。





CGIHTTPServer



Pythonにはcgiを動作させるための組み込みモジュール
「CGIHTTPServer」があります。(Python 2の場合)

CGIHTTPServer - CGI 実行機能付き HTTP リクエスト処理機構

これを使えば、簡単にアプリケーションサーバーが動かせそうです。

cgiスクリプトを配置するディレクトリの名称はデフォルトで
「cgi-bin」です。


path/cgi-bin/sample.pyを作成。


  1. # -*- coding:utf-8 -*-
  2. print('Content-type: text/html; charset=UTF-8\r\n')
  3. print('Hello, World!')




ターミナルを起動して、pathに移動。
CGIサーバーを起動します。


$ python -m CGIHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...




ブラウザでhttp://localhost:8000/cgi-bin/sample.pyを表示しようとすると、
コンソールにこんなエラーが。


Traceback (most recent call last):
File "/usr/lib/python2.7/CGIHTTPServer.py", line 248, in run_cgi
    os.execve(scriptfile, args, env)
OSError: [Errno 13] Permission denied




権限が足りないのかと思い、sudoで実行してもダメ。


$ sudo python -m CGIHTTPServer




cgiで実行しようとするスクリプトに実行権限が必要でした。


$ chmod +x cgi-bin/sample.py




権限をつけて再度アクセスすると次はこんなエラー。


Traceback (most recent call last):
File "/usr/lib/python2.7/CGIHTTPServer.py", line 248, in run_cgi
    os.execve(scriptfile, args, env)
OSError: [Errno 8] Exec format error




ファイルの先頭にシェバン (shebang) が必要でした。


  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. print('Content-type: text/html; charset=UTF-8\r\n')
  4. print('Hello, World!')




これで表示できました。

743_01.png



Python 3の場合は、http.serverに「--cgi」オプションをつけて起動すれば
同様の動作となります。


$ python3 -m http.server --cgi
Serving HTTP on 0.0.0.0 port 8000 ...







cgi



こちらのドキュメントを参考にしました。
cgi - CGI (ゲートウェイインタフェース規格) のサポート

デバッグ用にcgitbを使用すると便利とのこと。
わざとエラーになるプログラムで表示してみます。


  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import cgi
  4. import cgitb
  5. cgitb.enable()
  6. print('Content-type: text/html; charset=UTF-8\r\n')
  7. print('Hello, World!')
  8. # わざとエラーを発生させる
  9. error is here




こんな感じで、エラーとなった箇所を表示してくれました。

743_02.png


引数を追加すると、エラー内容をhtmlで保存してくれます。


  1. cgitb.enable(display=0, logdir='./')



ajax通信時のエラーデバッグで便利でした。






get値の取得




getされた値を取得してみます。
ブラウザで表示するURL
http://localhost:8000/cgi-bin/sample.py?query=symfo


  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import cgi
  4. import cgitb
  5. cgitb.enable()
  6. print('Content-type: text/html; charset=UTF-8\r\n')
  7. # パラメーターを取得
  8. form = cgi.FieldStorage()
  9. print(form['query'].value)




cgi.FieldStorage()で送信されたパラメーターを解析。
内容は辞書型に変換されるので、その中から値を取り出します。

743_03.png





post値の取得



postの場合もFieldStorageを使用した同様の処理となります。
postを送信するindex.htmlを作成。


  1. <!doctype html>
  2. <html lang="ja">
  3.     
  4. <html>
  5. <head>
  6.     <meta charset="UTF-8">
  7.     <title>cgi</title>
  8.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  9. </head>
  10. <body>
  11.     <form method="post" action="./cgi-bin/sample.py">
  12.         <input type="text" name="form_text"><input type="submit" value="send">
  13.     </form>
  14. </body>
  15.     
  16. </html>




cgi-bin/sample.py


  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import cgi
  4. import cgitb
  5. cgitb.enable()
  6. print('Content-type: text/html; charset=UTF-8\r\n')
  7. # パラメーターを取得
  8. form = cgi.FieldStorage()
  9. print(form['form_text'].value)




ちゃんとpostしたデータが受け取れていますね。

743_04.png

743_05.png




ajax通信



ここで使用したaxiosを使用し、ajax通信を行うサンプルを作ってみます。
Riot ajaxで取得したjsonデータをテーブルに表示する(axios使用)
https://github.com/mzabriskie/axios

ここではまったのですが、axios.postした値はform.fileに
json形式の文字列で送信されてきます。

form値をprintしてみて気が付きました。


FieldStorage(None, None, '{"ping":"value"}')




・index.html


  1. <!doctype html>
  2. <html lang="ja">
  3.     
  4. <html>
  5. <head>
  6.     <meta charset="UTF-8">
  7.     <title>cgi</title>
  8.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  9.     <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js"></script>
  10.     <script>
  11.     function button_click() {
  12.         axios.post('/cgi-bin/sample.py', {
  13.                 ping : document.getElementById('form_text').value
  14.             })
  15.             .then(function (response) {
  16.                 var result = document.getElementById('result');
  17.                 result.innerHTML = response.data['pong'];
  18.             })
  19.             .catch(function (error) {
  20.                 console.log(error)
  21.             });
  22.         
  23.         
  24.     }
  25.     </script>
  26. </head>
  27. <body>
  28.     <input type="text" name="form_text" id="form_text">
  29.     <input type="button" value="send" onclick="javascript:button_click()">
  30.     <div id="result"></div>
  31. </body>
  32.     
  33. </html>




・cgi-bin/sample.py


  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import json
  4. import cgi
  5. import cgitb
  6. cgitb.enable(display=0, logdir='./')
  7. print('Content-type: text/javascript; charset=UTF-8\r\n')
  8. # パラメーターを取得
  9. form = cgi.FieldStorage()
  10. # axiosからpostされた値は、fileに格納されている
  11. # json形式に変換
  12. post_json = json.load(form.file)
  13. # 送信データの先頭に「echo」をつけて返却
  14. result = {
  15.     u'pong' : u'echo -> ' + post_json['ping']
  16. }
  17. print(json.dumps(result))




適当な文字列を入力してsend。

743_06.png


狙い通りの応答が得られました。

743_07.png


【参考URL】

PythonでCGIを動かす(Python2, Python3)
Python: CGIHTTPServerでCGIスクリプトを処理

関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/11(火) 22:32:38|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<ブラウザ(JavaScript)で複数のファイルを一括ダウンロードさせる | ホーム | Riot ajaxなど非同期通信後の再描画>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1977-493d1c4c
この記事にトラックバックする(FC2ブログユーザー)