Ajax > jQuery

>

Ajax Python データ送受信

公開日 : 2024/02/02

最終更新日時 : 2024/03/13 10:48:04

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 python
成功!!

ちなみに 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
ajax python
結果は同じ