🥐 はじめに
こんにちは、tosane932です。
2026年5月からPythonの独学を始め、AIを活用しながらベーカリー向け売上管理アプリ「Bakery Hub」を開発しています。
今回で、Python・Web開発の基礎を学び直すシリーズも 第11時限目 になりました。
前回の第10時限目では、GET・POST・requestについて学びました。
ブラウザからサーバーへリクエストを送り、Flaskが受け取って処理する仕組みです。
今回は、その続きです。
ブラウザからリクエストを送ったあと、サーバーはどうやって処理結果を伝えるのでしょうか。
例えば、商品を登録できた場合と、入力内容が間違っていた場合。
サーバーは、どちらも同じ返事をするのでしょうか。
🐹「商品登録ボタンを押したら、登録完了って表示されたよ!」
🐹「でも、間違った数字を入力したときはエラーが出たんだよね……」
🐹「Pythonは、成功したのか失敗したのかをどうやって伝えてるんだろう?」
今回のテーマは HTTPステータスコードとエラー処理 です。
名前は少し難しそうですが、一つずつ見ていきます。
📖 第1章|HTTPステータスコードって何?
前回学んだGETとPOSTは、ブラウザからサーバーへ送るリクエストでした。
一方、サーバーからブラウザへ返すものをレスポンスと呼びます。
HTTPステータスコードは、そのレスポンスに含まれる3桁の数字です。
処理結果を簡潔に伝える役割があります。
リクエストとレスポンスの流れ
【ブラウザ】
「商品登録画面を見せて!」
│
│ GETリクエスト
▼
【Flask / サーバー】
商品登録画面を用意する
│
│ レスポンス
│ 200 OK
▼
【ブラウザ】
商品登録画面が表示される
🐹「200って数字が返ってきてるんだ!」
HTTPステータスコードの 200 は、一般的にリクエストが成功したことを表します。
ただし、成功や失敗を示す番号は200だけではありません。
例えば、次のようなコードがあります。
| ステータスコード | 意味 | 身近なイメージ |
|---|---|---|
200 |
OK | うまく処理できた |
400 |
Bad Request | 送られた内容に問題がある |
403 |
Forbidden | アクセスを許可できない |
404 |
Not Found | 指定されたものが見つからない |
500 |
Internal Server Error | サーバー側で問題が起きた |
🐹「404は見たことある!存在しないページを開いたときに出るやつだ!」
そうです。
あの404も、HTTPステータスコードの一つだったんですね。
📖 第2章|最初の数字で大まかな意味が分かる
HTTPステータスコードは、最初の数字によってグループ分けされています。
5つのグループ
| 分類 | 名前 | 大まかな意味 |
|---|---|---|
1xx |
情報レスポンス | 処理途中の情報 |
2xx |
成功レスポンス | リクエストが成功した |
3xx |
リダイレクト | 別の場所への移動など |
4xx |
クライアントエラー | リクエスト側に関係する問題 |
5xx |
サーバーエラー | サーバー側で問題が発生 |
最初から番号を全部覚える必要はなさそうです。
まずは、次の3つを押さえたいと思います。
2xx → 成功
4xx → リクエストに関係する問題
5xx → サーバー側の問題
🐹「じゃあ400番台と500番台は、問題が起きている場所が違うんだね」
ここが今回、大切なポイントです。
例えば、入力された商品名が条件に合わない場合は400を返すことがあります。
一方、データベースの保存処理で問題が発生した場合は500を返すことがあります。
どちらも登録に失敗していますが、失敗した理由が違うわけです。
📖 第3章|200 OK:正常に処理できた
まずは成功した場合です。
Bakery Hubの商品登録処理では、保存が完了すると次のコードが実行されます。
return render_template(
"success.html",
year=year,
month=month
)
render_template() は、HTMLテンプレートを使って表示する内容を作るFlaskの関数です。
ここでは登録完了画面の success.html を使っています。
コードの役割
| コード | 意味 |
|---|---|
render_template() |
HTMLテンプレートから表示内容を作る |
"success.html" |
使用するテンプレート |
year=year |
年の情報を渡す |
month=month |
月の情報を渡す |
return |
処理結果を返す |
ここには 200 という数字が書かれていません。
実はFlaskでは、正常なレスポンスを返す場合、ステータスコードを省略すると通常は200になります。
🐹「えっ!200って書いてなくても200になるの?」
そうなんです。
ただし、200はHTTPリクエストが成功したことを表すコードなので、どんな処理でもデータベース保存を保証するわけではありません。
今回の商品登録では、保存完了後にこの画面を返す構成になっています。
📖 第4章|400 Bad Request:入力に問題がある
次は400です。
Bakery Hubの商品登録では、登録する年月もフォームから送信しています。
例えば、1〜12月の範囲で指定する月に、13という数字が送られてきたらどうなるでしょうか。
実際のコードを見てみます。
if month < 1 or month > 12:
logger.warning("Rejected product update with out-of-range month.")
return "月は1から12で指定してください。", 400
🐹「あっ!ここに400がある!」
ここでは、月が1未満または12を超えているかを確認しています。
条件を分解してみる
month < 1 or month > 12
| 条件 | 意味 |
|---|---|
month < 1 |
1未満か |
or |
どちらかの条件が成立するか |
month > 12 |
12を超えているか |
例えば、
month = 13
なら、
13 < 1 or 13 > 12
となります。
右側の条件が True なので、if 文の中へ進みます。
そして、このreturn
return "月は1から12で指定してください。", 400
ここには、文字列と数字があります。
| 部分 | 役割 |
|---|---|
"月は1から12で指定してください。" |
レスポンスとして返すメッセージ |
400 |
HTTPステータスコード |
Flaskでは、このようにタプルの形でレスポンスの内容とステータスコードを指定できます。
🐹「なるほど!画面に表示する言葉と、HTTPの結果を一緒に返してるんだ!」
つまり、400は「入力が間違っています」といった状況を、HTTPの仕組みとして伝える役割を持っています。
📖 第5章|403と404の違い
ここで、少し似ているように感じる2つの番号を見てみます。
403 Forbidden
403は、アクセスを許可できない場合に使われます。
Bakery Hubには、利用者がアクセスできるデータを確認する処理があります。
その一部です。
if not current_user.is_authenticated:
abort(403)
ここでは、認証されていない場合に403を発生させています。
abort() は、Flaskで指定したHTTPエラーを発生させるための関数です。
🐹「return ..., 400 とは書き方が違うんだね」
そうですね。
HTTPステータスコードを指定する方法は一つではありません。
今回は、
return "メッセージ", 400abort(403)
という2種類の書き方が登場しました。
404 Not Found
一方の404は、指定されたページなどが見つからない場合です。
例えば、存在しないURLにアクセスしたとします。
GET /not-found-page
FlaskでそのURLを処理するルートが存在しなければ、通常は404が返されます。
403と404を比較
| コード | 状況の例 |
|---|---|
403 |
アクセスを許可できない |
404 |
指定されたページが見つからない |
🐹「403はアクセスできない、404は見つからない、って覚えると分かりやすいね」
なお、未ログイン状態を示すときなどには401が使われる場合もあります。
403との細かな違いは、認証や権限管理を学ぶときに改めて確認したいと思います。
📖 第6章|500 Internal Server Error:サーバー側の問題
次は500です。
400番台がリクエストに関係する問題だったのに対し、500番台はサーバー側の問題を表します。
例えば、商品を登録しようとしたとき、データベースへの保存に失敗する場合があります。
Bakery Hubには、次のような処理があります。
実コードから一部を抜粋
try:
# 商品の追加や更新などの処理(途中省略)
db.session.commit()
except SQLAlchemyError:
db.session.rollback()
logger.exception("Failed to save product master.")
return "商品マスタを保存できませんでした。", 500
※ 学習しやすいように、try 内の途中の処理を省略しています。
🐹「今度は try と except が出てきた!」
以前のPython基礎でも、例外処理について学びました。
ここでは、データベースへの保存などでSQLAlchemyの例外が発生した場合に、except SQLAlchemyError の処理へ進むようになっています。
コードを分けてみる
| コード | 役割 |
|---|---|
try |
例外が発生する可能性のある処理を実行する |
db.session.commit() |
DBへの変更を確定する |
except SQLAlchemyError |
指定した種類の例外を捕まえる |
db.session.rollback() |
未確定の変更を取り消す |
logger.exception() |
エラー情報をログに残す |
return ..., 500 |
保存失敗をHTTPの結果として返す |
なぜrollbackするのか?
例えば、3つの商品をまとめて登録するとします。
クロワッサン
あんぱん
食パン
途中で保存に失敗した場合、変更が中途半端な状態になってしまうと困ります。
そこで、rollback() によって未確定の変更を取り消します。
🐹「つまり、保存できなかったときの対応もコードに書いてあるんだ!」
そうなんです。
ただ成功する処理だけではなく、失敗した場合にどうするかも考える必要があります。
📖 第7章|例外とHTTPステータスコードは同じもの?
ここまで読んで、もう一つ疑問が出てきました。
🐹「except でエラーを捕まえるのと、400や500を返すのって同じこと?」
実は、別の仕組みです。
2つの違い
| 項目 | 役割 |
|---|---|
| Pythonの例外 | プログラムの処理中に起きた問題を知らせる |
| HTTPステータスコード | HTTPリクエストに対する結果を相手へ伝える |
例えば、商品の月が13だった場合。
これはアプリが想定している入力条件に合っていません。
でも、Pythonの例外が発生しなくても、if 文で判定して400を返せます。
一方、データベース操作中に例外が発生したら、except で捕まえたあとに500を返すことがあります。
【入力値が条件に合わない】
if文で検証
↓
400を返す
【データベース処理で例外が発生】
try内で例外発生
↓
exceptで捕まえる
↓
rollback()
↓
500を返す
🐹「なるほど!Pythonの例外を扱うことと、ブラウザへ結果を知らせることは別なんだね」
僕も最初は、どちらも「エラー」という言葉でまとめて考えていました。
でも役割を分けてみると、少し整理できました。
📖 第8章|302って何? エラーじゃないの?
ここまで200・400・403・404・500を見てきました。
最後に、もう一つだけ紹介します。
302 Found です。
302はエラーではなく、別のURLへの移動を案内するために使われるステータスコードです。
Bakery Hubのログアウト処理には、次のコードがあります。
return redirect(url_for("login"))
redirect() は、指定したURLへ移動するためのレスポンスを作ります。
Flaskの redirect() は、ステータスコードを指定しなければ通常302を使います。
ログアウト後の流れ
ログアウト
│
▼
Flaskがログアウト処理を実行
│
▼
302 リダイレクト
│
▼
ブラウザがログイン画面へ移動
🐹「302はエラーじゃなくて、別のページへ案内する番号なんだ!」
ステータスコードは、失敗したときだけに使うものではありません。
正常な処理やページ移動にも使われているんですね。
📖 第9章|ステータスコードをまとめて整理
今回学んだものを表にまとめてみます。
| コード | 意味 | Bakery Hubでの例 |
|---|---|---|
200 |
正常に処理できた | 商品登録完了画面を表示 |
302 |
別のURLへ案内する | ログアウト後にログイン画面へ移動 |
400 |
リクエストの内容に問題がある | 月に13を指定した |
403 |
アクセスを許可できない | 利用者の認証条件を満たしていない |
404 |
見つからない | 存在しないページへのアクセス |
500 |
サーバー側の問題 | DB保存時にエラーが発生した |
最初からすべての番号を暗記するより、
まずは最初の数字から、大まかな原因を推測できるようになりたいと思います。
200 → 成功した
302 → 別のURLへ移動する
400 → リクエスト内容に問題がある
403 → アクセスを許可できない
404 → 見つからない
500 → サーバー側に問題がある
🐹「404しか知らなかったけど、ほかの番号にもちゃんと意味があったんだね」
📝 第11時限目の理解度チェック
今回も、最後に5問で復習します。
まずは答えを見ずに考えてみます。
| 問題 | 内容 |
|---|---|
| Q1 | HTTPステータスコードは、リクエストとレスポンスのどちらに含まれる? |
| Q2 | 正常に処理できたことを示す代表的なコードは? |
| Q3 | 存在しないページにアクセスしたときの代表的なコードは? |
| Q4 | 400番台と500番台の大まかな違いは? |
| Q5 |
except SQLAlchemyError と return ..., 500 は同じ役割? |
✅ 解答例を見る
Q1. HTTPステータスコードはどちらに含まれる?
レスポンスです。
サーバーからブラウザへ、リクエストの処理結果を伝えます。
Q2. 正常に処理できたことを示す代表的なコードは?
200 OK です。
Q3. 存在しないページにアクセスしたときは?
404 Not Found です。
Q4. 400番台と500番台の違いは?
400番台はリクエストに関係する問題、500番台はサーバー側の問題を表します。
Q5. 同じ役割?
違います。
except SQLAlchemyError はPythonで特定の例外を捕まえる処理です。
return ..., 500 はHTTPレスポンスとして500を返します。
🐹 おわりに
今回は、HTTPステータスコードとエラー処理について学び直しました。
これまで404や500という数字を見たことはありましたが、正直なところ、それぞれ何が違うのか深く考えたことはありませんでした。
でも、Bakery Hubのコードを読んでみると、番号によって意味が違うことが分かりました。
特に印象に残ったのは、Pythonの例外処理とHTTPステータスコードは別の役割を持っているということです。
今まではどちらも「エラー処理」としてまとめて考えがちでした。
実際には、
- Pythonが問題を検知する
- 必要なら変更を取り消す
- HTTPレスポンスで結果を知らせる
という役割があります。
もちろん、今回の記事だけでエラー処理をすべて理解できたわけではありません。
HTTPステータスコードには、まだまだたくさんの種類があります。
ただ、400や500を見たときに、以前より少しは原因を考えられそうです。
🐹「404はページがない、400は送った内容に問題がある、500はサーバー側の問題……」
🐹「全部同じエラーじゃなかったんだね!」
これからもBakery Hubのコードを読みながら、知っているつもりだった基礎を、一つずつ理解し直していきたいと思います。
最後まで読んでいただき、ありがとうございました!
🔗 参考資料・関連リンク
公式ドキュメント
- MDN|HTTPレスポンスステータスコード
- MDN|400 Bad Request
- MDN|404 Not Found
- MDN|500 Internal Server Error
- Flask公式|Quickstart
- Flask公式|Handling Application Errors
🐹 Python基礎シリーズ|これまでの学習記録
Bakery Hub(旧sales_data_app)の実コードを教材に、Pythonの基本文法からWeb開発の仕組みまで学び直しています。
| 時限 | 学習テーマ | 記事 |
|---|---|---|
| 第1時限目 | 変数・データ型・比較演算子・if文 | 📖 読む |
| 第2時限目 | リスト・辞書・set・for文 | 📖 読む |
| 第3時限目 | 関数・引数・return・型ヒント | 📖 読む |
| 第4時限目 | モジュール・import・例外・try・except | 📖 読む |
| 第5時限目 | クラス・インスタンス・init・self・属性 | 📖 読む |
| 第6時限目 | f文字列・アンパック・内包表記・join | 📖 読む |
| 第7時限目 | strip・len・splitlines・スライス | 📖 読む |
| 第8時限目 | None・is・is not・isinstance | 📖 読む |
| 第9時限目 | CRUD・Create・Read・Update・Delete | 📖 読む |
| 第10時限目 | GET・POST・request | 📖 読む |
| 第11時限目 | HTTPステータスコード・エラー処理 | 📍 今回の記事 |
🥐 Bakery Hub
GitHub|Tosane Works
Bakery Hub|公開デモ
システム概要|実コードで学ぶページ
