カテゴリー
IT programming

エックスサーバー上でPythonのCGIを使用したJSONの送受信(Ajax)を行う

前回の記事を参考に、エックスサーバー上でPythonのCGIに対して、JSONの送受信をテストしたいと思います。

前回の記事はこちら。

https://1-10000th.com/python-cgi-500error/

やりたいこと

PythonをCGIにして、WEBページ(Javascitpt+Ajax)からJSONを送信して、Pythonで受信して加工して、JSONを返して、WEBページで表示する。

具体的には、WEBページ(tashizan.html)から入力xと入ちょくyを、Python(response.py)にAJAXでPOST送信して、Python内で足し算して、その結果をWEBページに戻す。

WEBページのコード(tashizan.html)

bootstrap4とjQueryを使用しています。

<!doctype html>
<html lang="ja">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>Python + Ajax</title>
</head>

<body>
    <div class="container">
        <h1>PythonとAjaxで足し算するよ</h1>
        <form>
            <div class="form-group">
                <label for="x">x</label>
                <input type="number" class="form-control" id="x" placeholder="">
            </div>
            <div class="form-group">
                <label for="y">y</label>
                <input type="number" class="form-control" id="y" placeholder="">
            </div>
            <div class="form-group">
                <label for="answer">answer ( x + y )</label>
                <input type="number" class="form-control" id="answer" placeholder="" readonly>
            </div>
        </form>
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script>
        $(function() {

            //keyup()でキーを入力するたびに発動
            $('input[type="number"]').keyup(function() {

                //リクエスト
                let request = {
                    x: $("#x").val() ? $("#x").val() : "0",
                    y: $("#y").val() ? $("#y").val() : "0",
                };

                console.log(request);

                url = "response.py"

                $.ajax({
                    type: "POST",
                    url: url,
                    data: JSON.stringify(request),
                    dataType: "json",
                    success: function(data) {
                        $('#answer').val(data['answer']);
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        console.log("ERROR:\n" + url + "\n" + textStatus + ":\n" + errorThrown);
                    }
                });
            });
        });
    </script>

</body>

</html>

Pythonのコード(response.py)

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
import json

data = sys.stdin.read()
params = json.loads(data)

# 数字かどうかを判断する関数
def is_num(s):
    try:
        float(s)
    except ValueError:
        return False
    else:
        return True

# 数字以外のものが飛んできたらとりあえず弾く
if is_num(params['x']) and is_num(params['y']): 

    result = {'answer': float(params['x']) + float(params['y'])}

    print("Content-type: application/json")
    print("\n\n")
    print(json.JSONEncoder().encode(result))
    print('\n')


結果

https://1-10000th.com/python-cgi/tashizan.html

注意点

  • 改行コードをLFにする(超重要)。
  • pythonファイルは権限を705もしくは755にする。
  • .htaccessにAddHandler cgi-script .pyを書く。

補足

なお、WEBページを経由せずに、SSH等でpythonプログラムの動作を確認するには、下記のようにしてpythonプログラムに、パイプでJSONを渡すことができる模様(sys.stdin.read()を使用しているので)。

JSONのキーもバリューもダブルクオテーションで囲むこと。

$ echo '{"x": "-12.5", "y": "64.3"}' | ./response.py 

実行結果↓

Content-type: application/json



{"answer": 51.8}

カテゴリー
IT programming

エックスサーバーでpythonでcgiを作る際に500エラーになったら原因は改行コード

ずっと500エラーが出続けて、解決するのに時間がかかってしまったため備忘録として残しておきます。誰かのためになったら。。。

やりたかったこと

エックスサーバーで、pythonをcgiとして動かしたかったです。hello.pyというファイルに、ブラウザからアクセスして、’Hello world’と表示するだけ。

方法

いろいろなページを拝見した結果、下記のことをすればエックスサーバー上でpythonがcgiとして動くことがわかりました。

  • pythonファイルが置かれているディレクトリに.htaccessを置き、下記を書く(.pyという拡張子はcgiですよという宣言)。
AddHandler cgi-script .py
  • SSHかFTPソフトかなにかで、pythonファイルの権限を705にする(755でもいいみたい)。SSHなら $ chmod 705 hello.py 的な。

pythonのコード

ページにHello worldと表示するpythonコード(hello.py / python3用)です。

#!/usr/bin/python3
# -- coding: utf-8 --
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
print ("Content-Type: text/html; charset=UTF-8;\n\n")
print ('Hello world')

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=’utf-8′)

というのは、文字化け防止のおまじないのようです。

謎の500エラー

500エラー

  • 断続的に発生する場合:
    CGIの負荷が大きい(CGIプロセスが多数動作している)。
  • 常に発生する場合:
    CGIのパーミッション設定に誤りがある。 / CGIのソースコードに問題がある。/ .htaccess の記述に誤りがある。

困りました。

「CGIの負荷が大きい」というのに引っかかった可能性はゼロではないでしょうが、Hello worldと表示するだけなので、極めてゼロに近いでしょう。

あとはパーミッションは設定したし、.htaccessも設定した。あとは「ソースコードに問題がある」ってことなんですが、上記のソースコードはどっからかコピーしたものですし間違っているとは思えない。。。一体何が原因なのか。

解決方法

一時間ぐらいかけて色々検証した結果、ソースコードの改行コードがCRLFではだめなことに気づきました。

これです(エディタはVisual studio code)。

 

これを、「CRLF」というところをクリックして、「LF」を選択すると下記のようになります。

 

ということで「LF」に変えて保存し直して、再度アクセス。

成功!