python でお気楽Webサーバを構築してCGIのテスト。

# はじめに
phtonを使ってお気楽にWebサーバを構築してみます。

- Webサーバ用のドキュメントルートの作成
- index.html の作成
- Webサーバの起動
- ブラウザで確認
- CGIオプションを付けてWebサーバの起動
- CGIの動作確認
- POST/GETでCGIにデータの引き渡し確認

という手順で構築してみます。

## 前提
python3環境が構築されていること。
OSにはWindows10を利用する。

##  Webサーバ用のドキュメントルートの作成

どこに作成してもいいです。
適当に python_http_server などという名前のフォルダを作成してみましょう。

~~~
C:\> cd \
C:\> mkdir python_http_server
C:\> cd python_http_server
C:\python_http_server>
~~~

## index.html の作成

C:\python_http_server> 直下に index.html を作成する。

~~~html:index.html
<html>
<head>
<title>
Title: Hello Python World
</title>
</head>
<body>
<h1>
Hello Python World
</h1>
</body>
</html>
~~~

このように見えます。

~~~
C:\python_http_server>dir/w
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は xxxx です

 C:\python_http_server のディレクトリ

[.]          [..]         index.html
               1 個のファイル                  97 バイト
               2 個のディレクトリ  xxxx バイトの空き領域
~~~

## Webサーバの起動

python には標準でWebサーバライブラリが存在します。
ドキュメントルートとして作成済のC:\python_http_server で以下のコマンドを実行します。

~~~
C:\python_http_server>python -m http.server 8080
~~~

※ポート番号を省略した場合デフォルト値は8000です。

python3は http.server ですが、python2 だとコマンドが異なります。

~~~
python -m SimpleHTTPServer 8080
~~~

## ブラウザで確認

http://localhost:8080 にアクセスしてみます。

![index_html.png](https://qiita-image-store.s3.amazonaws.com/0/255677/62f095a3-6bbd-69ce-6ffb-623509183025.png)

と出力されました。

なお Microsoft Edgeではセキュリティの観点からlocalhostというURLは標準では見られないので about:flags にアクセスして解除する必要があるります。

![about_flags_setting.png](https://qiita-image-store.s3.amazonaws.com/0/255677/b9763949-e0b6-b927-b772-50fc250e5191.png)

変更してもダメな場合は、Chromeなど別のブラウザで確認してください。

## CGI の実行
python3 でCGIを作成して実行させる場合は、

~~~
C:\python_http_server>python -m http.server 8080 --cgi
~~~

という　“--cgi”　オプションを付けて実行します。このとき cgi-bin というフォルダを作成し、その中にpython で作成したCGIを格納する必要があります。

例えば、

~~~python:helloworld_jp.py
print ("Content-Type: text/html\n");
print ("こんにちは　日本語！");
~~~

と記載してcgi-binフォルダに保存してみます。

## ブラウザで確認
http://localhost:8080/cgi-bin/helloworld_jp.py にアクセスすると…

![hello_japanese.png](https://qiita-image-store.s3.amazonaws.com/0/255677/dbed8024-189f-c943-770c-abbccfc5395b.png)

と表示されます。

## 日本語でエラー発生

python3で作成したCGIをSJISコード(ANSI)で保存していた場合、文字コードによる以下のようなエラーが起動したコマンドプロンプトで発生します。ブラウザは真白で何も表示されないので必ずUTF-8で保存してください。

~~~
127.0.0.1 - - [xx/xx/xx xx:xx:xx] command: C:\Anaconda3\python.exe -u C:\python_http_server\cgi-bin\helloworld_jp_sjis.py ""
127.0.0.1 - - [xx/xx/xx xx:xx:xx] b'  File "C:\\python_http_server\\cgi-bin\\helloworld_jp_sjis.py", line 2\r\nSyntaxError: Non-UTF-8 code starting with \'\\x82\' in file C:\\python_http_server\\cgi-bin\\helloworld_jp_sjis.py on line 2, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details\r\n'
127.0.0.1 - - [xx/xx/xx xx:xx:xx] CGI script exit status 0x1
~~~

日本語でおかしなことがあったらここをチェック！
https://qiita.com/goodboy_max/items/a35fd133141543f26845


## POST/GETでデータの引き渡し

POST/GETが簡単に実行できるようにHTMLファイルを作成します。
保存する文字コードはくれぐれも注意するように！

~~~html:post_get_test.html
<html>
<head>
<title>テストフォーム</title>
<meta http-equiv="content-type" charset="utf-8">
</head>
<body>
■POST
<form action="http://localhost:8080/cgi-bin/post_get_test.py" method="post">
  <div>
    <label for="name">名前</label>
    <input name="name" id="name" value="POST 名前">
  </div>
  <div>
    <label for="addr">住所</label>
    <input name="addr" id="addr" value="POST 住所">
  </div>
  <div>
    <button>POST実行</button>
  </div>
</form>
<hr>
■GET
<form action="http://localhost:8080/cgi-bin/post_get_test.py" method="get">
  <div>
    <label for="name">名前</label>
    <input name="name" id="name" value="GET 名前">
  </div>
  <div>
    <label for="addr">住所</label>
    <input name="addr" id="addr" value="GET 住所">
  </div>
  <div>
    <button>GET実行</button>
  </div>
</form>

参考<br>
https://docs.python.jp/3/library/cgi.html

</body>
</html>
~~~

実行するCGIのpythonファイルを作成し、cgi-bin 以下に配置します。
python の cgiモジュールは変数取得のためにGET/POSTメソッドによって
処理を変更する必要はないのでメチャ楽だ！

~~~python:post_get_test.py
import cgi
import os

# デバッグ用
import cgitb
cgitb.enable()

print ("Content-Type: text/html")
print()

print ("<html><body>")

form = cgi.FieldStorage()
form_check = 0

# formでの変数有無チェック
if "name" not in form or "addr" not in form:
  form_check = 1

print ("<h1>{0}変数出力</h1>".format(os.environ['REQUEST_METHOD']))

# パラメータエラー時の対応 
# python の cgiモジュールは変数取得のためにGET/POSTメソッドによって
# 処理を変更する必要はないのでメチャ楽だ！
if form_check == 1 :
  print ("<h2>ERROR !</h2>")
  print ("Please fill in the name and addr fields.")
else :
  print ("<b>名前: </b>", form["name"].value)
  print ("<b>住所: </b>", form["addr"].value)
 
print ("</body></html>")
~~~

http://localhost:8080/post_get_test.html にアクセスしてみます。

![post_get_test_html.png](https://qiita-image-store.s3.amazonaws.com/0/255677/e5335e4f-b1aa-6d4b-6fea-235cd7b8693c.png)

POST実行してみます。

![post_test_cgi.png](https://qiita-image-store.s3.amazonaws.com/0/255677/02ac4ab9-d906-5d56-b58c-78b2cbad62d0.png)

GET実行してみます。

![get_test_cgi.png](https://qiita-image-store.s3.amazonaws.com/0/255677/eba1883f-42b0-bafd-bf95-68b6ce967d18.png)


以上です。