3秒でわかる
前回のやり取りをサーバー側が覚えていない性質のこと。HTTP はこの方式を採り、必要な情報を毎回リクエストに載せるため、台数を増やして捌けます。
もう少し詳しく
どういうものか
ステートレスとは、1 回のリクエストを処理し終えたら、その内容をサーバーが保持しない性質です。HTTP はこの前提で設計されています。同じ人が続けて 2 回アクセスしても、サーバーから見れば無関係な 2 件です。
1 回目 GET /cart Authorization: <token>
2 回目 POST /checkout Authorization: <token> ← 毎回送るなぜ必要か
サーバーを増やせるからです。状態を持たないなら、リクエストがどのサーバーに届いても同じ結果になります。負荷が上がったら台数を足すだけで捌けますし、1 台落ちても他が引き継げます。状態をサーバーのメモリに置いた瞬間、この自由が消えます。
具体例
ログイン状態は、状態をサーバーの外に追い出して表現します。
// トークンを検証するだけ。誰がログイン中かをサーバーは覚えない
app.get("/api/me", (req, res) => {
const token = req.headers.authorization?.replace("Bearer ", "");
const user = verifyToken(token);
res.json({ id: user.id, name: user.name });
});セッション方式を使う場合も、置き場所をアプリのメモリではなく Redis やデータベースにすれば、サーバー本体はステートレスのままになります。
つまずきやすいところ
開発中は 1 台で動かすので、メモリに状態を持つコードでも問題なく動きます。本番でサーバーが 2 台になった途端「たまにログアウトする」という症状が出ます。原因は、2 台のメモリが別物だからです。
グローバル変数にカウンタや一時データを置く書き方も同じ落とし穴です。プロセスが再起動すれば消えますし、複数プロセスで動かせば値がずれます。手元で 1 プロセスしか動かさない開発環境ほど、この間違いに気付けません。
似た用語との違い
| ステートレス | ステートフル | |
|---|---|---|
| 状態の保持 | しない | する |
| 台数を増やす | 容易 | 振り分けの工夫が要る |
| 例 | HTTP、REST API | FTP、WebSocket の接続 |
WebSocket は接続を保ったまま状態を持つ方式で、チャットや通知のように継続的なやり取りが要るときに選ばれます。どちらが優れているという話ではなく、増やしやすさを取るか、やり取りの続きやすさを取るかの選択です。