0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで超シンプルWeb:実はCGIだけで動く話

Last updated at Posted at 2025-12-15

クラウド開発環境 PaizaCloud IDE (以下PaizaCloudと表記)を使って Hello World シリーズを書いています。今回はPython で CGI を試してみる という回です。Pythonの簡易サーバで HTTP と CGI を体験してみます。

PaizaCloudの具体的な利用方法は以下等を参考にしてください。
https://qiita.com/isy-nishida/items/4e9e49a83952b5eb46dd
クラウド開発環境PaizaCloudクラウドIDEのすすめ

🎯 目的
Webアプリを作ることではなく、
Web がどれだけシンプルな仕組みで動いているかを体験すること。

フレームワークを使うと見えなくなる
“Web の最小単位(HTTP & CGI)” をあえて自分の手で触ってみます。

📝 補足と前提について

本記事では、初学者の方向けに Web の仕組み(HTTP / CGI / フレームワーク)をできるだけシンプルに説明しています。正確さよりも「まず全体像がつかめること」を優先しているため、厳密な仕様や例外は意図的に省略しています。

より正確な技術仕様を調べたい場合は、HTTP RFC や各フレームワークの公式ドキュメントを参照してください。本記事はあくまで 最初の理解の足がかりとして読んでいただければ幸いです。

🌐 まず HTTP とは?(超概要)

HTTP(HyperText Transfer Protocol)は、
TCP/IP の「アプリケーション層」で動くテキスト通信のルール です。

  • ブラウザ → サーバへ 文字列でリクエスト
  • サーバ → ブラウザへ 文字列でレスポンス

つまり Web は本質的には

テキストの送受信

で動いています。

🌐 CGIとは?(Webの最小実装のひとつ)

CGI(Common Gateway Interface)は、

Webサーバが外部プログラムを実行し、
その標準出力を HTTPレスポンスとして返す仕組み

です。
つまり、

HTTPリクエスト → (CGI) → 標準出力 → HTTPレスポンス

という流れです。

🔍 HTTPリクエストは「環境変数」で渡される

例:

GET /cgi-bin/hello.py?name=nishida HTTP/1.1

CGIでは次のように渡されます:

HTTPの情報 CGIプログラムでの受け取り方
GETパラメータ 環境変数 QUERY_STRING
POSTデータ 標準入力(stdin)
Content-Type CONTENT_TYPE
Content-Length CONTENT_LENGTH

Webサーバが “HTTP → OSの入出力” に変換してくれる

というシンプルな構造です。

🔍 CGIプログラム → 「標準出力で HTTPレスポンスを返す」

最も重要なポイントです。

CGIプログラムは:

  • まず HTTPレスポンスヘッダ
  • 続いて 本文(HTMLなど)

print するだけ です。

🐍 Pythonで最小のCGI(Hello Web)

ファイル名:hello.py

#!/usr/bin/env python3
import os

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

query = os.environ.get("QUERY_STRING", "")

print("<html><body>")
print("<h1>Hello Python CGI</h1>")
print(f"<p>QUERY_STRING = {query}</p>")
print("</body></html>")

ポイント:

  • 先頭の Content-Type: が必須
  • QUERY_STRING で GETパラメータ取得
  • あとは print するだけ

📁 ディレクトリ構成

PaizaCloudのデフォルトでの例です。上記プログラムhello.pyを記述して保存します。

/home/ubuntu
 ├ hello.py
 └ cgi-bin/

🛠 Python CGI用にファイルを置く

mv hello.py cgi-bin/hello.py
chmod +x cgi-bin/hello.py

▶ Pythonの簡易サーバを起動する(CGI対応)

起動するのは、cgi-binの上のディレクトリです。
PaizaCloudの例では、/home/ubuntuです。

python3 -m http.server 8080 --cgi

🌍 ブラウザでアクセス(localhostの場合)

http://localhost:8080/cgi-bin/hello.py

※補足ですが、PaizaCloudで実行する場合は、PaizaCloudの地球アイコンであれば、localhostで起動出来ます。そこで表示されたURLを通常のブラウズにコピーして起動すれば外部のブラウザでも起動出来ます。

より詳細が必要な場合は、記事冒頭にも書いた通り、
以下のクラウド開発環境PaizaCloudクラウドIDEのすすめ の投稿を参考にしてください。
https://qiita.com/isy-nishida/items/4e9e49a83952b5eb46dd

PaizaCloudでのスクリーンショットの例
cgi1.png

GETパラメータつき:

http://localhost:8080/cgi-bin/hello.py?name=myname&lang=python

PaizaCloudでのスクリーンショットの例
cgi2.png

📌 実行結果(HTML)

ブラウザからからは画面上右クリックで、ページのソースを表示という流れで見えます。

<html><body>
<h1>Hello Python CGI</h1>
<p>QUERY_STRING = name=myname&lang=python</p>
</body></html>

📝【補足】#!/usr/bin/env python3 とは?

CGIプログラムの 1 行目に書く

#!/usr/bin/env python3

これは、このスクリプトを Python3 で実行してください という意味を持つ
“シバン行(shebang)”です。

CGI では Webサーバがスクリプトを 直接実行 するため、この行がないと正しく動かず、
500 Internal Server Error になりやすくなります。

✔ なぜ /usr/bin/env python3 を使うの?

Python3 のインストール場所は、環境によって次のように異なります。

  • /usr/bin/python3
  • /usr/local/bin/python3
  • ユーザー環境の ~/.local/bin/python3
  • Anaconda などの Python

そこで env を使うことで、

PATH(環境変数)から適切な python3 を自動的に探して実行してくれる

という利点があります。

✔ 一言でまとめると

#!/usr/bin/env python3
「どの環境でも Python3 を見つけて実行するための最も安全な書き方」
特に CGI では必須。

💡 Webの仕組みが腑に落ちるポイント

観点 Python CGIでの仕組み
HTTPレスポンスヘッダ print("Content-Type: text/html\n")
レスポンス本文 HTMLを print するだけ
GETパラメータ os.environ["QUERY_STRING"]
サーバとCGIプログラム 「環境変数+標準出力」で通信

Webは「文字列を返すだけ」で動いている。
これを感じられれば今回のゴールは達成です。

❗ よくあるエラーと対処

✔ 403 Forbidden

chmod +x cgi-bin/hello.py

✔ 500 Internal Server Error

Content-Type の行が抜けている。

✔ 404 Not Found

URLが /cgi-bin/hello.py になっていない。

📝【注意】CGI が動かない原因が「改行コード(CRLF)」の場合

前項のエラーと原因は確認したけど、まだ、なぜか

  • file not found
  • No such file or directory
  • 500 Internal Server Error

といったエラーになる場合、
スクリプト自体は存在しているのに動かないことがあります。

その原因の一つが、
改行コードが CRLF(Windows形式)になっていることです。
pythonのWebサーバーの画面(ログ)に表示されるのでなぜかなと思った場合は確認してみてください。

🔍 なぜ改行コードでエラーになるのか?

補足で説明した、CGI スクリプトの先頭の **シバン行(shebang)**ですが。

#!/usr/bin/env python3

この行の末尾が CRLF(\r\n になっていると、
Linux(Ubuntu) では次のように解釈されてしまいます。

/usr/bin/env python3\r

その結果、

「そんなファイルは存在しない」

と判断され、file not found エラーになります。

つまり、

Python が見つからないのではなく、
改行コードのせいで “別のコマンド名” として扱われている

という状態です。

🛠 対処方法:sed コマンドで改行コード(CRLF)を修正する

sed コマンドを使えば、
1行で CRLF → LF に変換できます。

実行例

sed -i 's/\r$//' post_form.py

複数ファイルまとめて変換する場合

sed -i 's/\r$//' cgi-bin/*.py

🔎 改行コードの確認方法(参考)

改行コードは file コマンドで確認できます。

file post_form.py

CRLF の場合、次のように表示されます。

with CRLF line terminators

✅ 修正後の確認ポイント

  • シバン行が正しく解釈される
  • chmod +x が正しく効く
  • CGI が正常に実行される

📌 ここでの改行コードに関するまとめ(重要)

  • CGI スクリプトは 改行コードに非常に敏感
  • Windows で作成 → Linux で実行する場合は特に注意
  • エラー内容が分かりにくく、原因に気づきにくい
  • CRLF 問題は環境依存トラブルの代表例

CGI が動かないときは、
まず「改行コード(CRLF)」を疑うのが実務的なコツです。

🏗️ フレームワークとは? (今後の発展のために補足)

フレームワークとは? そして CGI とどう関係するの?

今回やった CGI は、

  • HTTPリクエストを環境変数から読む
  • HTTPレスポンスを print で返す
    という Webの最小単位でした。

では、普段みんなが使っている Flask、Django、Rails、FastAPI、Laravel などの 「フレームワーク」は何をしているのでしょうか?

✔ フレームワークは “HTTPの面倒なところを全部まとめて管理してくれる仕組み”

フレームワークが内部でやっていることは実はシンプルです。

本質的な処理 CGIでの実装 フレームワークの内部
リクエストの解析 環境変数 QUERY_STRING を読む ルーターが /?id=1 を自動解析
POSTデータの読み込み 標準入力(stdin)を読む request.form["name"] のように扱える
HTTPレスポンス print("Content-Type: …") return jsonify(...) などで返す
HTML生成 print で手書き テンプレートエンジンで自動生成
ルーティング 自力でURLを判定 @app.get("/hello") で自動振り分け

つまり、

フレームワークは CGI の“面倒を全部ラップした層”

にすぎません。

✔ フレームワークを使っても、結局は「HTTP → プログラム → HTTP」だけで動いている

フレームワークがどれだけ高機能でも、内部では必ずこの流れになっています:

ブラウザ → HTTPリクエスト
              ↓
     (フレームワーク内部)
              ↓
プログラムの処理(Python/Rustなど)
              ↓
     (フレームワーク内部)
              ↓
ブラウザへ HTTPレスポンス

つまり、

フレームワークは Web を「楽に書くための道具」であり、
根本的な仕組みは CGI と全く同じ。

ということです。

🔍 なぜ今回 CGI を触る価値があるのか?

  • フレームワークを使うと HTTPの仕組みが“隠れる”
  • しかし本質は 文字列の入力と出力
  • CGI はそれを「生の形」で触らせてくれる
  • フレームワークのコードがなぜ動いているかが理解しやすくなる

たとえば FastAPI で:

@app.get("/hello")
def hello(name: str):
    return {"message": f"Hello {name}"}

と書けるのは、内部で

  • HTTPヘッダの解析
  • パラメータの抽出
  • JSON変換
  • レスポンス作成

すべて肩代わりしてくれているからです。

✨ まとめ:CGIでWebの本質が見えると、フレームワークも理解しやすい

  • Webの基本は「リクエスト(入力)→ レスポンス(出力)」
  • CGIはその仕組みを最も“生の形”で触れる
  • フレームワークはその上にある便利な層
  • 中身の理解があると応用(Python・Rust・Django・FastAPI など)が早くなる

CGIを知る = Webフレームワークの“裏側”を一度見ておくこと
これはエンジニアとして非常に強い経験になります。

🎯 全体のまとめ

  • HTTPは TCP/IP のアプリケーション層で動くテキストプロトコル
  • CGI = 標準出力で HTTPレスポンスを返す仕組み
  • Pythonでも CGI は数行で書ける
  • Webの本質を“直接”体験できる
  • フレームワークの前に理解すると強い

「Webって、まずはこんなにシンプルなんだ。そしてその上にいろいろな追加仕様が乗っかってきた。」
と実感できればOKです。

次回の以下に続きます。
Python CGI その2 「名前+ひとこと」をPOSTで受け取りファイル操作と検索を試す
https://qiita.com/isy-nishida/items/bbf0fe4a11d7986ea280

今回のCGIから、ファイル操作と検索で簡単なですが、「Webアプリの基礎」を作成してみます。
ありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?