jQueryとPythonでAjax

最終更新: 2017-09-11 00:04

Pythonで書いたプログラムのWebインターフェースを作りたかったので、Ajaxを使ってブラウザとPythonプログラム間でデータをやりとりするコードを書いた。これが最良の方法かどうかは分からない。

簡単な方法: Pythonでサーバーを立てる

サーバーをPythonで立てると簡単である。localで開発するときにはこの方法を使うといいだろう。

HTMLコード

<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>Ajax demo</title>
  </head>

  <body>
    <h1>Ajax demo</h1>
    <form id="form">
      <div><label>送信する数字</label><input type="number" id="number" value="0"></div>
      <div>
      <label>送信するテキスト</label>
      <textarea id="text"></textarea>
      </div>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    </div>
    <div id="result">
    </div>

    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function() {
      $('#form').submit(function() {
        event.preventDefault();
        var $form = $(this);
        $.ajax({
          url: 'http://localhost:8000/cgi-bin/sample.py',
          type: 'post',
          dataType: 'text',
          data: {
            number: $('#number').val(),
            text: $('#text').val()
          },
        })
        .done(function(response) {
          $('#result').html(response);
        })
        .fail(function() {
          $('#result').html('Failed.');
        });
      });
    });
    </script>
  </body>
</html>

Pythonコード

カレントディレクトリにcgi-binというフォルダを作り、cgi-bin/sample.pyに保存する。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cgi, cgitb

cgitb.enable()

form = cgi.FieldStorage()
text = form.getfirst("text")
n = form.getfirst("number")
sequence_list = []

print('Content-type: text/html\nAccess-Control-Allow-Origin: *\n')
print("<p>送信された数字: {}</p>".format("None" if n is None else int(n)))
print("<p>送信されたテキスト: {}</p>".format(text))

ヘッダーでAccess-Control-Allow-Origin: *を指定しないと

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

というエラーが出る。

サーバーの実行

cgi-binと同じ階層のディレクトリでサーバーを実行する。Pythonのバージョンによってコマンドが異なる。

Python2の場合

python -m CGIHTTPServer

Python3の場合

python -m http.server --cgi

サーバーを起動した状態で、用意したHTMLをブラウザで開けば動作確認ができる。

面倒な方法: nginxを使う

以上のようにして作ったhtmlファイルをgithub.ioに置いて動かそうとしたところ、

Mixed Content: The page at '**********' was loaded over HTTPS, but requested an insecure script '******************'. This request has been blocked; the content must be served over HTTPS.

のようなエラーが出て動作しなかった。

github.ioはhttpsを使っているのに対し、上記の方法で立てたサーバーはhttpなので通信がブロックされてしまったようだ。これを回避するためにnginxでhttps通信を行うように設定した。

以下の説明はSetting up Nginx and uWSGI for CGI scriptingの抜粋である。

nginxのインストールやLet's encryptでhttpsを使う設定は説明しない。

nginxの設定を変更する

/etc/nginx/conf.d/default.conf/cgi-bin/にアクセスされたときの設定を書き加える。

例として自分の現在の設定ファイルを書いておく。

server {
    listen 80;
    server_name localhost;
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl;
    server_name  localhost;

    ssl_certificate /etc/letsencrypt/live/kivantium.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/kivantium.net/privkey.pem;

    location / {
        # ルートにアクセスされた時の設定
    }
    location /cgi-bin/ {
        include uwsgi_params;
        uwsgi_modifier1 9;
        uwsgi_pass 127.0.0.1:9000;
    }
}

設定を変更したらrestartする。

sudo service nginx restart

uWSGIの設定・実行

まずはインストールする

curl http://uwsgi.it/install | bash -s cgi ~/uwsgi

~/uwsgi_config.iniに以下のように書く

[uwsgi]
plugins = cgi
socket = 127.0.0.1:9000
chdir = /home/kivantium/cgi-bin/
module = pyindex
cgi=/cgi-bin=/home/kivantium/cgi-bin/
cgi-helper =.py=python

起動する

sudo -u www-data ~/uwsgi ~/uwsgi_config.ini

この状態で~/cgi-binに先ほどのsample.pyを置いておけば、HTMLファイルのAjax通信先をhttps://example.com/cgi-bin/sample.pyのように書き換えるだけで動作する。