Python を CGI で実行する設定
環境
CentOS Stream release 9
Apache/2.4.57 (CentOS Stream)
Server API FPM/FastCGI
Xserver VPS
当初、Ajax と Python 間でデータの送受信を行おうとしたが PythonファイルをCGI として実行させる部分がうまくいかない。
Ajax や fetch で Python ファイルは呼べない・・・Flask を使ってどうこう・・・、すぐに博識ぶってくるバカがいるようだが、そんな単細胞な奴の見解などどうでもいい。
ここで言ってるのは ブラウザに Python ファイルを CGI として解釈させデータのやり取りを行う方法についてだ。どういうブログラムを書くかじゃなく、どうやって目的を果たすかだ。
ってなわけでまずは CGI モジュールの存在を確認するところから始める。
モジュールの場所
cd /etc/httpd/modules && ls
下記三つの CGI モジュールが含まれているのを確認
mod_cgi.so mod_cgid.so mod_fcgid.so
CGI モジュール関連の設定ファイルを探す
cd /etc/httpd/conf.modules.d && ls
output
00-base.conf 00-dav.conf 00-mpm.conf 00-proxy.conf 00-systemd.conf 10-fcgid.conf
10-proxy_h2.conf 00-brotli.conf 00-lua.conf 00-optional.conf 00-ssl.conf 01-cgi.conf
10-h2.conf 20-php80-php.conf.org
これらは httpd.conf 内でインクルードされているファイルだ。
10-fcgid.conf 、01-cgi.conf といった CGI に関連した2つのファイルがある。
vi 01-cgi.conf
# This configuration file loads a CGI module appropriate to the MPM
# which has been configured in 00-mpm.conf. mod_cgid should be used
# with a threaded MPM; mod_cgi with the prefork MPM.
<IfModule !mpm_prefork_module>
LoadModule cgid_module modules/mod_cgid.so
</IfModule>
<IfModule mpm_prefork_module>
LoadModule cgi_module modules/mod_cgi.so
</IfModule
vi 10-fcgid.conf
LoadModule fcgid_module modules/mod_fcgid.so
10-fcgid.conf と 01-cgi.conf で読み込む CGI モジュールの選択を行っている。
そういう理由でか 00-base.conf のロードモジュール一覧には CGI モジュールは含まれていない。
とうぜんながら振り分けがうまくできてない場合は CGI モジュールは読み込まれない。
ならば 00-base.conf に下記を追記して確実に読み込ませる作戦に出る。
vi /etc/httpd/conf.modules.d/00-base.conf
下記を追記する
LoadModule cgi_module modules/mod_cgi.so
追記する候補は下記の3つで後々判明したことだが、自分の環境では mod_cgi.so でしか成功しなかった。
LoadModule cgi_module modules/mod_cgi.so LoadModule cgid_module modules/mod_cgid.so LoadModule fcgid_module modules/mod_fcgid.so
あとは httpd.conf の設定。
httpd.conf の設定
vi /etc/httpd/conf/httpd.conf
<Directory "/var/www/html">
⌇
Options Indexes FollowSymLinks ExecCGI
AllowOverride all
Require all granted
AddHandler cgi-script .cgi .pl .py
⌇
</Directory>
<IfModule mime_module>
⌇
#AddHandler cgi-script .cgi
↓
AddHandler cgi-script .cgi .pl .py
⌇
</IfModule>
結局、上記のように設定して httpd 再起動でようやく Python を CGI として動作させることができた。
cgi-bin が CGI 御用達のディレクトリのようだが、状況によっては呼び出し側ファイルと呼ばれる側ファイルが離れ離れになるなど七めんどくさいことが予想されるのでここではシカトする。
systemctl restart httpd
Ajax と Python 間でデータの送受信
Ajax から json データを Python に送り、Python から json データを取得するといったブーメラン方式による単純な内容。
Python (test.py)
#!/var/www/html/test/my_env/bin/python import json import sys def main(): data = sys.stdin.read() params = json.loads(data) val1 = int(params['val1']) val2 = int(params['val2']) val3 = params['val3'] print("Content-type: application/json; charset=UTF-8\n") response = {"value1" : val1, "value2" : val2, "要約" : val3} print(json.dumps(response, indent=2, ensure_ascii=False)) if __name__ == '__main__': main()
冒頭の python パスは自分の環境に応じて書き換える必要がある。
Python ファイルのパーミッションは 705 に設定
chmod 705 test.py
シェルから json データを送り返り値を確認
echo '{"val1": "64", "val2": "128", "val3": "Ajax Python データ送受信"}' | ./test.py
output
Content-type: application/json; charset=UTF-8
{
"value1": 64,
"value2": 128,
"要約": "Ajax Python データ送受信"
}
Ajax を含んだ index.php
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ajax Python データ送受信</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <script> $(function(){ $.ajax({ type: 'post', url: './test.py', headers: { "Content-Type" : "application/json; charset=UTF-8", "X-HTTP-Method-Override" : "POST" }, data : JSON.stringify({ "val1" : 64, "val2" : 128, "val3" : "Ajax Python データ送受信" }), dataType : 'json', success : function(response) { let result = JSON.parse(JSON.stringify(response)); console.log(result); $('.value1').text('value1 : ' + result.value1); $('.value2').text('value2 : ' + result.value2); $('.description').text('要約 : ' + result['要約']); }, error : function(request, status, error) { console.log(request.responseText); alert(request.responseText); } }); }); </script> </head> <body> <div class="container"> <ul class="result"> <li class="value1"></li> <li class="value2"></li> <li class="description"></li> </ul> </div><!--/container--> </body> </html
Python からの返り値を index.php 内にあるリストタグにそれぞれ流し込む。
index.php のあるサイトurlでアクセス。
https://example.com 例
outoput
成功!!
ちなみに Ajax でなく fetch だと
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>fetch Python データ送受信</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <script> $(function(){ const asyncAwaitFunc = async () => { await fetch("./test.py", { method: "POST", body: JSON.stringify({ "val1" : 64, "val2" : 128, "val3" : "Ajax Python データ送受信" }), headers: { "content-type": "application/json; charset=UTF-8", Accept: "application/json", }, }) .then(response => response.json()) .then(data => { let result = JSON.parse(JSON.stringify(data)); console.log(result); $('.value1').text('value1 : ' + result.value1); $('.value2').text('value2 : ' + result.value2); $('.description').text('要約 : ' + result['要約']); }) .catch((error) => console.log(error)); } asyncAwaitFunc(); }); </script> </head> <body> <div class="container"> <ul class="result"> <li class="value1"></li> <li class="value2"></li> <li class="description"></li> </ul> </div><!--/container--> </body> </html
outoput
結果は同じ