Python独習!

習得したPython知識をペイフォワード

PythonでWebサーバーを立てる!

2021/01/27 更新

Pythonでクライアント・サーバーアプリケーションを作ってみたい
http.serverを使うことで自分のパソコンにサーバーを立てることができる。

解説

クライアント・サーバーアプリケーションは下図のイメージ。

python-client-server

クライアント

例えばChromeなどのWebブラウザがクライアントになり、ブラウザからサーバーに何らかの要求を出す。(上図だと a × b を計算する要求を出す)

サーバー

ブラウザからもらった要求に従って何らかの処理をする。(上図だと a × b を計算して、その結果 c をブラウザに返す)

サンプルプログラム

ブラウザに a と b の2つの数値を入力すると、a と b を掛け算した結果が表示される、というプログラムを作ってみる。
練習ということで、http.serverモジュールを使ってローカルサーバーを立てる。これでパソコン1台でクライアント・サーバーの動作を見ることができる。
python-client-server

ディレクトリの階層

pyファイルが2つ必要になる。一つはサーバー自体(cgiserver.py)、もう一つがブラウザに表示する内容(kakezan.py)。それぞれのpyファイルを保存する場所は以下のようにする。
python-client-server


サーバーへのアクセス方法

ブラウザのアドレスバーに kazezan.py のパスを入力する。具体的には以下のように。

http://localhost:8000/cgi-server/kakezan.py

(注)"localhost" 部分をローカルループバックアドレス(127.0.0.1)にするよう紹介しているサイトがあったが、自分の環境では動作しなかった。

ソースコード

サーバー
# cgiserver.py
# python 3.8.1

import http.server

server_address = ("", 8000)
handler_class = http.server.CGIHTTPRequestHandler # ハンドラを設定
server = http.server.HTTPServer(server_address, handler_class)
server.serve_forever()
ブラウザの表示内容
# kakezan.py
# python 3.8.1
# coding: utf-8

import cgi
import sys
import io
import re

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding = 'utf-8')        #printで出力する内容をutf-8にする
print('Content-Type: text/html; charset=UTF-8\n')                           #ファイルの種類を定義

#ブラウザに表示する内容を記述
## HTMLを変数html_bodyに代入している
## %sで変数ssを受けている
html_body = """
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Python CGI program</title>
</head>
<body>
    <p>aとbに数字を入れてください。</p>

    <form action="/cgi-bin/13_sum_001.py" method="post">
        <span>a: </span><input type="text" name="text1"><br>
        <span>b: </span><input type="text" name="text2"><br><br>
        <input type="submit" name="submit" value="計算">
    </form>

    <p>a x bは %s です。</p>
    
</body>
</html>"""

form = cgi.FieldStorage()
a = form.getvalue('text1', '')                                              #FieldStorageの中からキーがtext1の要素を拾う
b = form.getvalue('text2', '')                                              #FieldStorageの中からキーがtext2の要素を拾う

if re.compile("^\d+\.?\d*\Z").match(a) and re.compile("^\d+\.?\d*\Z").match(b):     #aとbが数値であるかどうかを調べる
    aa = float(a)
    bb = float(b)
    ss = round(aa * bb, 5)

else:
    ss = "N/A"
    
print (html_body % (ss))                                                    #cgiプログラムにおけるprintはクライアントへの返信。
/* -----codeの行番号----- */