PythonとHTMLとの連携の一環として、HTML(Javascript)からajax通信(非同期通信)を行い、Python側ではCGIで受信するという流れでデータ応答を確認してみました。 これは、ajaxとサーバー間でGET通信とPOST通信によるデータ受け渡し方法です。本記事ではコードが実行された際の通信方法をご紹介します。
本記事の読者層は以下の方を想定しています。
- HTMLとPython間でajax通信(非同期通信)でデータ受け渡しをしたい方
- JavascriptとPython間でajax通信(非同期通信)でデータ受け渡しをしたい方
HTML+Python間通信の基礎
Raspberry PIなどの小型コンピューターを利用してロボット開発・作成をしてみたい方などが多いのではないでしょうか。特に、遠隔操作で利用されるHTML画面からPythonプログラムを動かすHTML-Python通信はとても重宝する代物です。
今回はJavascriptのAjax(「Asynchronous JavaScript and XML」の略)を利用してサーバーへ情報を伝達する方法を紹介します。Ajaxとは簡単に言えば、JavaScriptでサーバー側と非同期通信を行うための技術になります。Ajaxの便利なところは、リクエスト中であっても、WEBアプリ上で操作ができなくなることがないという点です。これらAjaxの技術は、GoogleマップやGmail、Facebookなど、メジャーなWebサイトやツールでよく見かけるものです。
それでは、HTML+pythonの通信の流れを以下にご説明します。
以下の図は、HTML(JavaScript)をAjaxにより非同期通信を行い、Python側ではCGIで受信するという流れです。
Ajax上では、サーバー側へGET通信とPOST通信が行えます。特にPOST通信を利用してサーバーへメッセージの書き込みやデータの更新などを行ってみます。
これをCGI (Common Gateway Interface)で受けるという形になります。CGIの特長はどの言語を用いても作成することがプログラムであるため、Pythonでも「モジュール」としても使用可能です。今回はPython側の通信手段をCGIで行います。
Python-HTML(javascript)通信のテストの準備
今回のJavascriptとHTMLの連携確認のテスト環境は以下の通りです。
- Ubuntu 18.04 LTS+apache2.4 (server側)
- JavaScript jquery-3.5.1.js
- Python 3.6.9 (serer側)
【手順1】JavascriptでAjaxが使用できるかどうか確認
サーバー側に以下のhtmlファイルを置いて手動でアクセスできるか確認してみます。
今回はLinux Ubuntu18.04 LTSを利用して、外部からアクセスが可能なディレクトリ「var/www/html」にて作業を行います。
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7\
LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript">
$.ajax({
success : function(response){
alert('成功');
},
error: function(){
//通信失敗時の処
alert('通信失敗');
}
});
</script>
</head>
これをクライアントのブラウザ上(Chromeブラウザを推奨)で自身のURL(今回は「https://daraberu.aa0.netvolante.jp」としています)を開くと以下のようにブラウザ上で以下のポップアップされます。
「成功」が表示されれば「Javascript」+「Ajax」の使用ができます。そしたら次のステップへ進みます。
【手順2】Python3がインストールされているか確認
Python3のインストールをサーバー側へ行います。インストールの詳細は以下の記事を参照頂くとして、ここでは、既にインストールされている前提で進めます。
それではPython3のインストール先をwhichコマンドで確認してみます。ディレクトリ先は後で示すPythonプログラムにて利用致しますのでメモしておいて下さい。サーバー側で以下のコマンドを実行してみて下さい。
$which python3
/usr/bin/python3
$python3 --version
Python 3.6.9
「/usr/bin/python3」をメモしておきましょう。
本記事では、Python3のバージョン 3.6.9を利用しています。
【手順3】CGIがインストールされているか確認
サーバー条でCGI言語を利用します。まず、CGIを有効にするために以下の手順でApache上でCGIが使用できる状況にします。
①CGIのモジュールを有効化します。
以下のコマンドでCGIを有効化できます。
$ sudo a2enmod cgid
②configファイルの設定:apache2.conf
Ubuntuサーバー上の「/etc/apache2/」ディレクトリ上に「apache2.conf」があります。こちらに以下を追記記載します。
<Directory /var/www/>
Options Indexes FollowSymLinks ExecCGI
AllowOverride all
Require all granted
AddHandler cgi-script .cgi .py
</Directory>
今回用いる「pythonファイル」と「htmlファイル」はともに「/var/www/html」に置く予定です。このため、<Dicrectory …..>のディレクトリの指定はその上層「/var/www/」で問題ありません。
注意点
configファイルの設定を間違えると既にインストールしているwordPress等、他のwebアプリにも影響があるため書き換えは慎重にお願いします。
③apacheの再起動
configファイル「apache2.conf」の設定を反映させるため、以下のコマンドでapacheを再起動します。
$sudo /etc/init.d/apache2 restart
apache2の設定方法などの詳細は以下の記事をご参照ください。
PythonとJavascriptの連携テスト環境
①HTMLファイルのコード
ajaxをJavascriptで動かす以下のHTMLファイルを「/var/www/html」に入れ込みます。
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript">
$(function(){
$.ajax({
url: './test.py',
type: 'post',
data: {data: 'HTML-test'}
}).done(function(data){
console.log(data);
}).fail(function(){
console.log('failed');
});
});
</script>
</head>
<body>
<div>ajax-Python test</div>
</body>
</html>
このファイルは後ほどブラウザから、「http://(ご自身のドメイン名)/Ajax-test.html」にてアクセスして結果を確認します。
②Pythonファイルのコード
次に、python3のCGI経由でajax通信を読み取るコードを作成します。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#print("content-Type: text/plain\n")
import cgi
storage = cgi.FieldStorage()
print('Status: 200 OK')
print('Content-Type: text/html\n')
data = storage.getvalue('data')
recieve = data + ":Success!"
print(recieve)
以下、簡単ですが、これらコードを解説します。
まずファイル先頭に「/usr/bin/python3」を一番最初に加えます。
以下のようにajaxから受け渡されたdata(値)をcgi.Fieldstorage()でpython上に格納する。
cgi.FieldStorage()
その後、data=’HTML-python’が格納されます。
data = storage.getvalue('data')
以下は、受け渡す際のおまじないです。(エラーにならないように宣言しておきます。)
print('Status: 200 OK')
print('Content-Type: text/html\n')
このコードをコマンドプロンプト上のPythonで実行しようとすると以下のエラーがでますが「data」(値)が送られてきていないので、この時点で心配する必要はありません。
$ python3 test.py
Traceback (most recent call last):
File "test.py", line 14, in <module>
recieve = data + ":Success!"
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
500 Internal Server Errorの解決方法
一番のはまりどころは、以下に示すChromeブラウザツール上で「500 internal server error」というエラー表示されたところです。このエラーでかなりの時間ロスをしました。
例えば、今回のエラーは、下記のようにChrome上での検証画面から確認できます。上記過程で、実行にともないコンソール表示で「failed」を示したことがあります。
どこでエラーが発生するかを確認するため、下図の「Network」タブをクリックするとテーブル上に「status」コードがでてきてエラー500を出している赤字の「test.py」が問題であることがわかります。
私の場合は、Chormeの言語設定を英語設定で使用していたためか、日本語表示で最初に記載していた「成功!」という表示ができずに(recieve = data + “:成功!”の部分)、「test.py」でエラー発生していました。日本語表記「:成功!」の部分を英語表記「:success!」に直した結果、このエラーが消えてうまくいきました。(上記のPythonコードでは修正済みです。)
ブラウザから実行した通信結果
以下結果を示します。
Chrome画面(下図左側はHTML画面表示@Chromeの検証画面)
Chromeブラウザ上で「ajax-Python test」と表示され(左上側), Console上で「HTML-test:Sccess!」(右下側)と表示されていればajaxg通信に成功しています。
これにてPythonとHTML間の通信が確立しました。
厳密には、HTML上のJavascriptからajaxを利用して、「html-test」というデータをPythonで書いたCGI (test.py)へ送って、その返答である「HTML-test:success!」という文字列をajaxで呼び出してHTML表示させています。なんとも面倒くさい方法です。
今回CGIを使用しましたが、モジュール自体、負荷が大きいこと、セキュリティ上の問題も多いことからレンタルサーバーでは使えない場合があります。
もう1つ、python上でsysモジュールを使う方法もありますが、本環境化のLinuxサーバーでは「sys.stdin.readline()」でAjaxからのPostデータを読み込めませんでした。他のサイトでも同様に通信ができないという報告もちらほら見られるようです。
出来る方がいたら教えて頂けたら幸いです!
XMLやJSONの型を利用してデータの「受け取り」と「受け渡し」をする方法
本記事は、Ajaxの非同期通信として簡単なレスポンスの手順をお伝えしました。実際には、XMLやJSON (Javascript Pbject Notation)の型を利用することで同様に複数のデータをやり取りできます。
更に複雑なHTML-Python間で通信をする場合は、FlaskやFastAPI, DjangoなどのPython用定番フレームワークを勉強してみるのも良いかもしれません。これらWEBフレームワークの詳細に関しては以下の記事をご参照ください。
まとめ
本記事ではJavaScriptとPythonの連携による通信手法の解説をおこなった。
- PythonとHTML間の通信にはJavaScript中で非同期通信Ajaxを使う方法がある。
- ✔ サーバー内でPythonのCGIによる受け渡しを行い通信できることを確認した。
次回の記事をご期待下さい。どうぞよろしくお願いいたします。
コメント