- ネットワーク
405 Method Not Allowedと501の違い|Allowと直し方・原文
結論
405 Method Not Allowed は「そのメソッドは知っているが、このURLでは受け付けない」、501 Not Implemented は「そのメソッド(機能)をサーバーが実装していない」という意味です。405には使えるメソッドを並べた Allow ヘッダーが必ず付き、GET で開けるのに POST で405になるときは、送り先のURL(フォームの action・静的ファイル・CORS のプリフライト)を疑います。
この記事でわかること
- 405と501の違いと、RFC 9110 の定義の原文・Allow ヘッダーの実物
- nginx・Apache・Python http.server・FastAPI・Flask・Django・Express で実際に返した405・501の原文
- 静的ファイルへの POST・フォームの action・CORS のプリフライト OPTIONS が405になる再現と直し方
サーバーは、届いたリクエストの「メソッド(GET・POST など動詞の部分)」をまず見ます。その動詞を知らなければ501、知っているが送り先のURLでは使えなければ405です(URLそのものが無ければ404)。
flowchart TD
R[リクエストが届く] --> K{メソッドを<br>知っている?}
K -->|いいえ| N[501<br>Not Implemented]
K -->|はい| M{この URL で<br>使える?}
M -->|いいえ| A[405<br>Method Not Allowed<br>Allow で案内]
M -->|はい| OK[200 など]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| 405 method not allowed とは | メソッドは分かるが、このURLでは受け付けない(Allow ヘッダーつき) | 405 Method Not Allowedとは |
| 501 not implemented とは | サーバーがそのメソッド・機能を実装していない(サーバー側のエラー) | 501 Not Implementedとは |
| 405エラーが出た(見る人) | URLを確かめる・再読み込み・別の経路で開く。多くはサイト側の直し | 405エラーが出たときの対処 |
| GETは開けるのにPOSTで405 | 静的ファイルへのPOST・フォームのactionの誤り・CORSのプリフライト | GETで開けるのにPOSTで405になる典型 |
| nginx の「405 Not Allowed」 | HTMLなどの静的ファイルにPOSTした。error_page 405 =200 か、APIへ中継 | nginxとApacheで405・501になる原因 |
| Express で POST が404になる | 既定は405ではなく404「Cannot POST」。405を返すには自分で書く | フレームワーク別の405の応答原文 |
| CORS error で OPTIONS が405 | プリフライトのOPTIONSにルートが無い。CORSのミドルウェアを入れる | CORSのプリフライトOPTIONSが405になる |
| API で404・405・501・415・422 の使い分け | URL→メソッド→Content-Type→内容の順に判定する | REST APIでの使い分け |
確認環境:Ubuntu 24.04.5 LTS の上で、nginx 1.24.0(Ubuntu)と Apache 2.4.58(Ubuntu)を自分の設定ファイルで 127.0.0.1 のポートに起動し、静的ファイルへの POST・PUT・未知のメソッド(FOO)・TRACE・未対応の Transfer-Encoding を送って405・501・403・400・413 を返しました。Python 3.13.18 の http.server、FastAPI 0.162.0(Starlette 1.10.0・uvicorn 0.54.0)、Flask 3.1.3(Werkzeug 3.1.9)、Django 6.1.2、Express 5.3.0(Node.js 22.23.4)も同じ機械で動かし、応答は curl 8.5.0 の curl -v で確かめました。ブラウザの表示と CORS のプリフライトは Google Chrome for Testing 153.0.8010.12(Playwright 1.63.0・日本語の画面)で再現しています。405・501・Allow の定義は RFC 9110 と RFC 9112 の原文、MDN の日本語ページ、ロードバランサーとレンタルサーバーの挙動は AWS とエックスサーバーの公式ページで確かめました。図は mermaid で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「405 Method Not Allowedと501の違い|Allowと直し方・原文」
405と501の違い(一覧表)
この節では、405と501が何を意味し、誰が直すものなのかが一覧で分かります。
405は「メソッドは認識しているが、このリソースでは対応していない」というクライアントエラー、501は「サーバーがその機能を実装していない」というサーバーエラーです。 400番台と500番台に分かれているのは、405は「送る側がメソッドやURLを変えれば通る」、501は「サーバー側が実装しない限り通らない」という違いがあるからです。
| 405 Method Not Allowed | 501 Not Implemented | |
|---|---|---|
| 意味 | メソッドは知っているが、対象のリソースでは受け付けない | そのメソッド(機能)をサーバーが実装していない |
| 分類 | 4xx(クライアントエラー) | 5xx(サーバーエラー) |
| 必須のヘッダー | Allow(使えるメソッドの一覧) | なし(Retry-After を付けてもよい) |
| 典型例 | HTMLファイルに POST、GET だけのAPIに PUT | 見たことのないメソッド(FOO)、http.server への POST |
| 直す人 | 送る側(メソッド・URL)か、受ける側(ルートの定義) | サーバー側(機能を実装する・別のソフトに替える) |
| キャッシュ | 既定でキャッシュ可能(RFC 9110) | 既定でキャッシュ可能(RFC 9110) |
窓口にたとえると
見分ける問い:「別のURL(窓口)なら同じメソッドが通るか」
405 Method Not Allowedとは(RFC 9110の定義とAllowヘッダー)
この節では、405の正確な定義と、必ず付く Allow ヘッダーの意味が分かります。
RFC 9110(HTTP Semantics)の 15.5.6 は、405を次のように定義しています。
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource. The origin server MUST generate an Allow header field in a 405 response containing a list of the target resource's currently supported methods.
MDN の日本語ページは「リクエストメソッドをサーバー側で認識しているが、対象のリソースでは対応していないことを示します」と説明し、405の応答には対応しているメソッドの一覧を含む Allow ヘッダーを生成しなければならない、としています。
Allow ヘッダーは、RFC 9110 の 10.2.1 で「対象のリソースが対応していると公表するメソッドの集合」と定義され、書き方はメソッド名をコンマで区切るだけです。
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, PUT
手元で Apache に PUT を送ったときの応答です。Allow に GET・POST・OPTIONS・HEAD・TRACE が並び、「この URL には PUT 以外のこれらを送れる」ことが分かります。
$ curl -v -X PUT http://127.0.0.1:47002/thanks.html
> PUT /thanks.html HTTP/1.1
> Host: 127.0.0.1:47002
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 405 Method Not Allowed
< Server: Apache/2.4.58 (Ubuntu)
< Allow: GET,POST,OPTIONS,HEAD,TRACE
< Content-Length: 220
< Content-Type: text/html; charset=iso-8859-1
<
<title>405 Method Not Allowed</title>
<p>The requested method PUT is not allowed for this URL.</p>
- Allow が空(
Allow:だけ)の405もあります。 RFC 9110 は、空の Allow は「そのリソースはどのメソッドも許可していない」ことを示し、設定で一時的に無効化されたときに起こり得る、としています。手元では Apache でTraceEnable Offにして TRACE を送ると、Allow:が空の405になりました。 - Allow は405以外の応答(OPTIONS への 200 など)に付けてもよい(MAY)とされています。
- 405は、特に指定が無ければキャッシュされ得る(heuristically cacheable)応答です。
501 Not Implementedとは(RFC 9110の定義と返る場面)
この節では、501の正確な定義と、どんなときに501が返るのかが分かります。
RFC 9110 の 15.6.2 は、501を次のように定義しています。
The 501 (Not Implemented) status code indicates that the server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.
405との線引きは、同じ RFC 9110 の 9.1(メソッドの概要)にまとめて書かれています。
An origin server that receives a request method that is unrecognized or not implemented SHOULD respond with the 501 (Not Implemented) status code. An origin server that receives a request method that is recognized and implemented, but not allowed for the target resource, SHOULD respond with the 405 (Method Not Allowed) status code.
同じ 9.1 には「All general-purpose servers MUST support the methods GET and HEAD. All other methods are OPTIONAL.」とあり、MDN の日本語ページも、サーバーは GET と HEAD には対応する必要があるので、これらに501を返してはいけない、と説明しています。
| 501が返る場面 | 根拠 | 手元で確かめた |
|---|---|---|
| サーバーが知らないメソッド(FOO など) | RFC 9110 9.1 | Apache(nginx・uvicorn は405、Node は400) |
| 実装していないメソッド(do_POST が無い) | RFC 9110 9.1 | Python http.server |
| 未対応の Transfer-Encoding(gzip など) | RFC 9112 6.1「SHOULD respond with 501」 | nginx(Apache・uvicorn・Node は400) |
| 実装しているどのメソッド名より長いメソッド名 | RFC 9112 3「SHOULD respond with a 501」 | (ドキュメントのみ) |
| 設定で意図して返した501 | nginx の return 501 |
nginx |
| ロードバランサー・WAF が返す501 | AWS・エックスサーバーの公式ページ | (ドキュメントのみ) |
MDN は、501には「指定された時点が経過した後であればリクエストを再試行できる」ことを伝える Retry-After を付けてもよく、501も既定でキャッシュ可能だ、としています。
405になる(メソッドは知っている)
HTML・画像などの静的ファイルに POST・PUT・DELETE
GET だけ定義した API のURLに POST
応答に Allow が付く。送る側が直せることが多い
501になる(サーバーが実装していない)
見たことのないメソッド名・未対応の転送符号化
簡易サーバーに POST(http.server など)
サーバー側が実装するか、別のサーバーに替える
405エラーが出たときの対処(見ている人向け)
この節では、Web サイトを使っていて「405 Not Allowed」「Method Not Allowed」が出たときに、自分でできることが分かります。
405は、ほとんどの場合サイト側の直しが要るエラーですが、見ている人の操作で変わることもあります。 順に試します。
URL を確かめ、アドレスバーから開き直す
フォームを送った直後に出た405は、送り先のURLがHTMLファイルなどになっている。アドレスバーの URL をそのまま Enter で開き直す(GET で開く)と、ページ自体は表示できることが多い。
「再送信」の確認は、いいえを選ぶ
再読み込みで「フォームを再送信しますか」と出たら、同じ POST をもう一度送ることになる。405は何度送っても同じなので、URL をクリックして GET で開く。
別のブラウザ・シークレットウィンドウ・別の回線で試す
拡張機能や、途中のプロキシ・WAF がメソッドを変えたり止めたりしていることがある。自分の環境だけで出るかを切り分ける。
サイトの管理者に「URL・操作・時刻・画面の文言」を伝える
「405 Not Allowed/nginx」のように画面にソフトの名前があれば、そのソフトが返している。何を押したときに出たかが直す側の手がかりになる。
501 はサーバー側の問題として扱う
WordPress の投稿やメールフォームの送信で501が出るときは、レンタルサーバーの WAF の設定が関わることがある(公式の記述は後述)。利用者側の操作では直らないので、管理者に伝える。
Chromeでの405・501の見え方(HTTP ERROR 405)
この節では、405・501のときにブラウザに何が表示されるのかと、表示から何が分かるのかが分かります。
画面は、サーバーが本文を返したかどうかで変わります。 手元で405・501を返し、Chrome(日本語の画面)で開いたときの表示を並べました。
| 返した場所 | ブラウザに見えた表示 |
|---|---|
| nginx の静的ファイルにフォームを POST | 405 Not Allowed/nginx/1.24.0 (Ubuntu) |
| Apache の静的ファイルに PUT | Method Not Allowed/The requested method PUT is not allowed for this URL. |
| Apache に未知のメソッド | Not Implemented/FOO not supported for current URL. |
本文の無い405(Express で res.status(405).end()) |
このページは動作していません/この問題が何度も発生する場合は、サイト所有者にお問い合わせください。/HTTP ERROR 405 |
| 本文の無い501 | このページは動作していません/127.0.0.1 では現在このリクエストを処理できません。/HTTP ERROR 501 |
- 「HTTP ERROR 405」「HTTP ERROR 501」の画面は、サーバーが本文の無い応答を返したときに、Chrome が代わりに出す画面です。 本文があれば、サーバーが返した HTML がそのまま表示されました。
- DevTools のコンソールには
Failed to load resource: the server responded with a status of 405 (Not Allowed)のように、ステータスの理由の文字列(nginx は Not Allowed、Apache は Method Not Allowed)がそのまま出ました。 - 画面の下に
nginx・Apacheの名前があれば、アプリより手前の Web サーバーが返した405・501です。
GETで開けるのにPOSTで405になる典型3つ
この節では、「ページは開けるのに、送信ボタンを押すと405」という最も多いパターンの原因と直し方が分かります。
同じURLでも、GET と POST では受け付ける側が違います。 静的ファイル(HTML・画像)は GET で読むものなので、POST を送ると Web サーバーが405を返します。
1静的ファイルへの POST
フォームの送り先が /thanks.html のような HTML ファイル。nginx は「405 Not Allowed」を返す。送り先をアプリ(API)のURLにするか、nginx の error_page 405 =200 $uri; で HTML を返す。
2フォームの action・method の誤り
action の綴り違い・末尾の「/」の有無・method="post" の付け忘れ。リダイレクト(301・302)で POST が GET に変わり、GET 専用のURLに届くこともある。
3CORS のプリフライト OPTIONS
JavaScript の fetch で別オリジンに DELETE・JSON の POST を送ると、ブラウザが先に OPTIONS を送る。OPTIONS のルートが無いと405になり、画面では CORS エラーに見える。
1つ目を手元で再現しました。<form action="/thanks.html" method="post"> のフォームを nginx 上で送ると、Chrome の画面は「405 Not Allowed/nginx/1.24.0 (Ubuntu)」になりました。curl では次のとおりです。
$ curl -v -d 'email=a@example.com' http://127.0.0.1:47001/thanks.html
> POST /thanks.html HTTP/1.1
> Host: 127.0.0.1:47001
> Content-Length: 19
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 405 Not Allowed
< Server: nginx/1.24.0 (Ubuntu)
< Content-Type: text/html
< Content-Length: 166
<
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.24.0 (Ubuntu)</center>
</body>
</html>
同じ HTML を GET で開くと 200 です。nginx のこの405には Allow ヘッダーが付きません(RFC 9110 では MUST ですが、静的ファイルの応答では付かないことを手元で確かめました)。Apache は同じファイルへの POST を GET と同じように扱い 200 を返したので、Web サーバーによって結果が違います。
nginxとApacheで405・501になる原因と直し方(ログの原文)
この節では、nginx と Apache がメソッドごとに何を返すのか、ログに何が残るのか、設定でどう直すのかが分かります。
同じ静的ファイルに7種類のメソッドを送った結果です。 nginx は GET・HEAD 以外をすべて「405 Not Allowed」にし、Apache は知っているメソッドは405、知らないメソッドは501と返し分けました。
| 送ったメソッド | nginx 1.24(静的ファイル) | Apache 2.4.58(静的ファイル) |
|---|---|---|
| GET | 200 | 200 |
| POST | 405(Allow なし) | 200(GET と同じ扱い) |
| PUT・DELETE | 405(Allow なし) | 405・Allow: GET,POST,OPTIONS,HEAD,TRACE |
| OPTIONS | 405 | 200・Allow つき |
| TRACE | 405 | 200(TraceEnable Off なら405・Allow 空) |
| FOO(未知) | 405 | 501・Allow つき |
POST+Transfer-Encoding: gzip |
501 | 400 |
nginx の設定と結果
nginx 1.24.0 を次の設定で 127.0.0.1:47001 に起動しました(ログの場所などの行を省いています)。
server {
listen 127.0.0.1:47001;
root /path/to/www;
location /files/ { # 読み取り専用(limit_except は 403 になる)
limit_except GET HEAD { deny all; }
}
location /post-ok/ { # 静的ファイルへの POST を許す
alias /path/to/www/;
error_page 405 =200 $uri;
}
location /upload/ { # PUT は実装していない、と自分で 501 を返す例
if ($request_method = PUT) { return 501; }
return 204;
}
location /api/ { # アプリへ中継(405 はアプリが返す)
proxy_pass http://127.0.0.1:47004/;
}
}
| 送ったもの | 応答 | error.log の文言 |
|---|---|---|
| POST /thanks.html | 405 Not Allowed | なし(access.log に "POST /thanks.html HTTP/1.1" 405 166) |
| POST /files/a.txt(limit_except) | 403 Forbidden | access forbidden by rule |
| POST /post-ok/thanks.html | 200(HTML を返す) | なし |
| PUT /upload/a | 501 Not Implemented | なし(access.log に 501) |
| POST+Transfer-Encoding: gzip | 501 Not Implemented | client sent unknown "Transfer-Encoding": "gzip" while reading client request headers(info) |
| POST /api/items(中継先が GET だけ) | 405・allow: GET(FastAPI の応答がそのまま) |
なし |
limit_exceptで止めたメソッドは405ではなく403になります。 nginx の公式ドキュメントどおり、limit_exceptの中はdenyなどのアクセス制限なので、結果は「access forbidden by rule」の403です。- 静的ファイルへの POST を通したいときは
error_page 405 =200 $uri;が定番です。POST の本文は捨てられ、HTML がそのまま返ります。 - nginx の405は error.log に出ません。access.log の9番目の欄(ステータス)で探します。
Apache の設定と結果
Apache 2.4.58 を自分の httpd.conf で 127.0.0.1:47002 に起動し、/files/ を <LimitExcept GET HEAD>Require all denied</LimitExcept> で読み取り専用にしました。
$ curl -v -X FOO http://127.0.0.1:47002/thanks.html
> FOO /thanks.html HTTP/1.1
>
< HTTP/1.1 501 Not Implemented
< Server: Apache/2.4.58 (Ubuntu)
< Allow: GET,POST,OPTIONS,HEAD,TRACE
< Content-Length: 202
< Connection: close
<
<title>501 Not Implemented</title>
<h1>Not Implemented</h1>
<p>FOO not supported for current URL.<br />
</p>
error.log には次の行が残りました。
[core:error] [client 127.0.0.1:43512] AH00135: Invalid method in request FOO /thanks.html HTTP/1.1
[authz_core:error] [client 127.0.0.1:43498] AH01630: client denied by server configuration: /path/to/www/files/a.txt
[http:info] [client 127.0.0.1:40118] AH01595: TRACE with body is not allowed for /thanks.html
| 送ったもの | 応答 | 読み取れること |
|---|---|---|
| FOO /thanks.html | 501・Allow つき | AH00135: Invalid method。知らないメソッドは501 |
| PUT /thanks.html | 405・Allow つき | 知っているが、このファイルには使えない |
| POST /files/a.txt(LimitExcept) | 403 | AH01630: client denied by server configuration |
| TRACE(本文つき) | 413 | TRACE に本文は付けられない |
TRACE(TraceEnable Off) |
405・Allow:(空) |
意図して無効化したメソッド |
Apache の <Limit>・<LimitExcept> も、nginx の limit_except と同じく403です。 「このメソッドは使えない」と伝えたいのに403になっている、というときはこの設定を疑います。
Python http.serverの501と、405を正しく返す書き方
この節では、python -m http.server に POST すると501になる理由と、自作のハンドラーで404・405・501を返し分ける書き方が分かります。
http.server は、do_POST のような「メソッド名のついた関数」が無いメソッドをすべて501にします。 公式ドキュメントのとおり、SimpleHTTPRequestHandler には GET と HEAD しかありません。
$ python3 -m http.server --bind 127.0.0.1 47005
$ curl -v -d x=1 http://127.0.0.1:47005/thanks.html
> POST /thanks.html HTTP/1.1
>
< HTTP/1.0 501 Unsupported method ('POST')
< Server: SimpleHTTP/0.6 Python/3.13.18
< Content-Type: text/html;charset=utf-8
< Content-Length: 357
<
<p>Error code: 501</p>
<p>Message: Unsupported method ('POST').</p>
<p>Error code explanation: 501 - Server does not support this operation.</p>
サーバー側のログには code 501, message Unsupported method ('POST') と残りました。PUT・DELETE・OPTIONS・FOO も同じ501です。静的ファイルの確認用サーバーなので、フォームの送信先には使えません。
自作するときは、「URLが無い→404」「URLはあるがメソッドが違う→405+Allow」「メソッドの関数が無い→501(親クラスに任せる)」の順で返し分けます。send_error(405) は Allow を付けないので、自分で send_header します。
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
ALLOWED = {"/items": ["GET", "HEAD"], "/orders": ["POST"]}
def _route(self):
allowed = self.ALLOWED.get(self.path)
if allowed is None: # URL そのものが無い → 404
self.send_error(404)
return False
if self.command not in allowed: # URL はあるがこのメソッドは受けない → 405
self.send_response(405)
self.send_header("Allow", ", ".join(allowed)) # 405 には Allow が必須
self.send_header("Content-Length", "0")
self.end_headers()
return False
return True
def do_GET(self):
if self._route():
body = b'{"items":[]}'
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_POST(self):
if self._route():
self.send_response(201); self.send_header("Content-Length", "0"); self.end_headers()
# do_PUT などを定義しないメソッドは、親クラスが 501 を返す
HTTPServer(("127.0.0.1", 47010), Handler).serve_forever()
GET /items -> HTTP/1.0 200 OK
POST /items -> HTTP/1.0 405 Method Not Allowed Allow: GET, HEAD
PUT /items -> HTTP/1.0 501 Unsupported method ('PUT')
GET /nothing -> HTTP/1.0 404 Not Found
フレームワーク別の405の応答原文(FastAPI・Flask・Django・Express)
この節では、よく使うフレームワークに「GET だけ定義したURLへ POST」を送ったとき、何番が返り Allow に何が入るのかが、実行した結果で分かります。
FastAPI・Flask・Django は405と Allow を自動で返しますが、Express の既定は404です。 未知のメソッド(FOO)は Node.js が HTTP の解析の段階で400にしました。
| フレームワーク | GET だけのURLに POST | Allow の中身 | 未知のメソッド FOO |
|---|---|---|---|
| FastAPI 0.162.0(uvicorn) | 405・{"detail":"Method Not Allowed"} |
allow: GET(HEAD は含まれない) |
405 |
| Flask 3.1.3(Werkzeug) | 405 METHOD NOT ALLOWED・HTML | Allow: GET, HEAD, OPTIONS |
405 |
| Django 6.1.2(require_GET) | 405・本文なし | Allow: GET |
405 |
| Django 6.1.2(View の post だけ) | GET に405 | Allow: POST, OPTIONS |
405 |
| Express 5.3.0(Node.js 22) | 404・Cannot POST /items |
なし | 400(Node が接続を閉じる) |
FastAPI:Allow は自動、HEAD は自分で足す
$ curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"x"}' http://127.0.0.1:47004/items
> POST /items HTTP/1.1
>
< HTTP/1.1 405 Method Not Allowed
< server: uvicorn
< allow: GET
< content-type: application/json
<
{"detail":"Method Not Allowed"}
手元で気づいた点が2つあります。
@app.getだけのURLに HEAD を送ると405になりました。 Starlette のRouteは GET に HEAD を自動で足しますが、FastAPI のAPIRouteは足しません。@app.api_route("/items/{id}", methods=["GET", "HEAD", "DELETE"])のように書くと HEAD が 200 になり、PUT への405の Allow もHEAD, DELETE, GETと全部並びました。- 同じ関数に
@app.getと@app.deleteを2つ重ねた場合、PUT への405の Allow はDELETEだけでした。ルートが2本に分かれ、先に一致した1本の Allow だけが返るためです。1本のURLに複数メソッドを持たせるならapi_route(methods=[...])にまとめます。
Flask と Django:405 に Allow が付く
$ curl -i -X POST http://127.0.0.1:47008/items # Flask: methods=["GET"]
HTTP/1.1 405 METHOD NOT ALLOWED
Server: Werkzeug/3.1.9 Python/3.13.18
Allow: GET, HEAD, OPTIONS
<title>405 Method Not Allowed</title>
<p>The method is not allowed for the requested URL.</p>
$ curl -i -X POST http://127.0.0.1:47009/items # Django: @require_GET
HTTP/1.1 405 Method Not Allowed
Server: WSGIServer/0.2 CPython/3.13.18
Allow: GET
Django のクラスベースビューは、定義していないメソッドを http_method_not_allowed が405にし、Allow には定義済みのメソッドと OPTIONS が入りました(Allow: POST, OPTIONS)。
Express:既定は404。405を返すには自分で書く
$ curl -i -X POST http://127.0.0.1:47003/items # app.get('/items') だけ
HTTP/1.1 404 Not Found
X-Powered-By: Express
<pre>Cannot POST /items</pre>
$ curl -v -X FOO http://127.0.0.1:47003/items
< HTTP/1.1 400 Bad Request
< Connection: close
「Cannot POST /items」は、Express がそのメソッドのルートを見つけられなかったときの404の本文です。 URL の打ち間違いと同じ扱いになるので、「URLはあるのにメソッドが違う」ことを伝えたいなら405を自分で返します。1本のURLなら app.route().all()、全体に効かせるならルート定義の後ろに次のミドルウェアを置きます。
app.get('/items', (req, res) => res.json([{ id: 1 }]));
app.post('/orders', (req, res) => res.status(201).json({ ok: true }));
app.delete('/orders/:id', (req, res) => res.sendStatus(204));
// ルート定義の後ろに置く:同じパスに別メソッドの定義があれば 405 + Allow、無ければ 404
app.use((req, res, next) => {
const allow = new Set();
for (const layer of app.router.stack) {
if (layer.route && layer.match(req.path)) {
Object.keys(layer.route.methods).forEach(m => allow.add(m.toUpperCase()));
}
}
if (allow.size === 0) return next(); // 404 へ
if (allow.has('GET')) allow.add('HEAD');
res.status(405).set('Allow', [...allow].join(', ')).json({ error: 'method_not_allowed' });
});
POST /items -> 405 Allow: GET, HEAD
GET /orders -> 405 Allow: POST
PUT /orders/5 -> 405 Allow: DELETE
GET /nothing -> 404 Cannot GET /nothing
Node.js の HTTP の解析器は、知らないメソッド名を受け取ると本文の無い400を返して接続を閉じました。Express のコードには届かないので、501を返したくても返せません。
CORSのプリフライトOPTIONSが405になる(Chromeで再現)
この節では、「CORS エラー」と表示されたときに、本当の原因がサーバーの OPTIONS への405であることがある理由と、直し方が分かります。
ブラウザは、別のオリジンへ DELETE や JSON の POST を送る前に、同じURLへ OPTIONS(プリフライト)を送ります。 OPTIONS のルートが無いと、GET だけのURLに POST したときと同じ理屈で405になり、プリフライトが失敗して本番のリクエストは送られません。
flowchart TD
J[JS の fetch DELETE] --> P[プリフライト<br>OPTIONS /items/1]
P -->|405 ルートなし| E[CORS エラー<br>Failed to fetch]
P -->|200 CORS ヘッダーあり| G[本番の DELETE]
G --> OK[JS が 200 を読める]
127.0.0.1:47006 のページから、CORS のミドルウェアが無い FastAPI(47004)と、ある FastAPI(47007)へ fetch(..., { method: 'DELETE', headers: { 'Content-Type': 'application/json' } }) を送りました。
[Chrome のコンソール]
Access to fetch at 'http://127.0.0.1:47004/items/1' from origin 'http://127.0.0.1:47006' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
no-cors-middleware -> TypeError: Failed to fetch
with-cors-middleware -> status 200
[サーバーのログ:ミドルウェアなし]
INFO: 127.0.0.1:57374 - "OPTIONS /items/1 HTTP/1.1" 405 Method Not Allowed
[サーバーのログ:CORSMiddleware あり]
INFO: 127.0.0.1:48754 - "OPTIONS /items/1 HTTP/1.1" 200 OK
画面は CORS のエラーでも、サーバーから見ると OPTIONS への405です。 直し方は、OPTIONS に自分で答えることではなく、フレームワークの CORS の仕組みを入れることです。FastAPI では次の数行です。
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://127.0.0.1:47006"],
allow_methods=["GET", "POST", "DELETE"],
allow_headers=["Content-Type", "Authorization"],
)
- 1DevTools のネットワークのタブで OPTIONS の行を見る405 なら OPTIONS のルートが無い。サーバーのログでも OPTIONS の行を探す
- 2CORS のミドルウェアを、ルートより前に入れるFastAPI の CORSMiddleware、Express の cors パッケージ、Django の django-cors-headers
- 3allow_methods に本番のメソッドを入れるDELETE を使うなら DELETE を。既定が GET だけのものもある
- 4nginx を手前に置くなら OPTIONS をアプリへ通す静的ファイルの location に OPTIONS が落ちると nginx が405を返す
CORS のエラーの文言ごとの直し方は、関連記事「CORSエラーの原因と解決方法|エラーメッセージ別に解説」で扱っています。
REST APIでの使い分け(404・405・501・415・422)
この節では、API を作る人が、405・501と混同しやすいコードをどの順で判定すれば迷わないかが分かります。
「URL → メソッド → 本文の形式 → 本文の内容」の順に判定すると、返すコードがぶれません。 405と501は2段目で決まります。
- 1メソッドをサーバーが知らない → 501 Not ImplementedWeb サーバーやフレームワークが先に返す。自分で書くことは少ない
- 2URL が無い → 404 Not Foundどのメソッドでも存在しない
- 3URL はあるがそのメソッドは受けない → 405+Allow読み取り専用のリソース・コレクションへの DELETE
- 4本文の形式(Content-Type)を受けない → 415 Unsupported Media TypeJSON の API に XML を送った
- 5形は読めたが内容が決まりに合わない → 422(または400)必須の項目が無い・値の範囲外
| ケース | 返すコード | 補足 |
|---|---|---|
| GET /users/1 はあるが PUT を受けない | 405 | Allow: GET, HEAD, DELETE |
| /users というコレクションに DELETE(全件削除を許さない) | 405 | 意図して受けないメソッド |
| 存在しない ID の GET | 404 | URL が無い |
| 見たことのないメソッド名 | 501(Apache)・405(nginx・uvicorn)・400(Node) | 手元の結果。自分で書く必要はほぼ無い |
| JSON の API に text/plain を送った | 415 | FastAPI は JSON 以外の本文に 422 を返す設計 |
| 必須の項目 name が無い | 422 または 400 | プロジェクトで揃える |
| 読み取り専用モードで PUT を止めた | 405(Allow 空も可)か 503 |
一時的なら 503+Retry-After |
| 機能として作っていないエンドポイント | 404(URL ごと無い) | 「未実装」でも 501 ではなく 404 が普通 |
405の本文は RFC 9457(Problem Details)の形に揃えると、クライアントのエラー処理を共通にできます。形の決め方は関連記事「APIエラーレスポンス設計|RFC 9457準拠のJSON例と実装コード」で、URL とメソッドの設計は関連記事「REST APIの設計|URL・ステータスコード・エラー形式の決め方」で扱っています。
ロードバランサー・WAF・レンタルサーバーが返す405・501
この節では、アプリではなく、手前の層が405・501を返す場合を、公式ページで確かめられる範囲で説明します。
アプリのログに来ていないのに405・501になるときは、手前の層が返しています。
| 返している層 | 何が起きるか(公式の記述) | 確かめること |
|---|---|---|
| AWS Application Load Balancer | HTTP 405:クライアントが TRACE を使った(ALB は未対応)。HTTP 501:未対応の Transfer-Encoding(対応は chunked と identity)、または WebSocket が target optimizer 有効のターゲットグループへ届いた | ALB のアクセスログ。ターゲットのログに行が無い |
| エックスサーバーの WAF | サーバーパネルの CGI「メールフォーム」1.3.1(2024年8月15日)の修正内容に「WAF有効時の501エラー表示」がある。WAF の「コマンド」対策は kill・ftp・mail・ping・ls 等の文字列を検知する。設定の反映には最大30分(旧パネルは1時間) | WAF を一時的に無効化して再現するか。投稿内容にコマンドの語があるか |
| Web サーバーの規則(limit_except・LimitExcept) | 405ではなく403(手元で確認) | error.log の access forbidden by rule/AH01630 |
| Web サーバーの静的ファイル | nginx は405、Apache は POST を 200・PUT を405(手元で確認) | access.log の行とソフト名 |
WordPress の投稿で501が出る話は、レンタルサーバーの WAF が本文中の語を検知して止めている例として多く報告されています。公式の案内があるのは上の範囲なので、WAF を一時的に無効化して再現するかどうかで切り分けます。無効化したままにせず、再現を確かめたら戻します。
よくあるエラー・つまずき(原文つき)
この節では、405・501のまわりで見る文言と、意味・直し方の対応が分かります。
| 見た文言(原文) | 出た場所 | 意味と直し方 |
|---|---|---|
405 Not Allowed/nginx/1.24.0 |
nginx | 静的ファイルに POST など。送り先をアプリにするか error_page 405 =200 $uri; |
The requested method PUT is not allowed for this URL. |
Apache | 静的ファイルに PUT・DELETE。送り先をアプリにする |
FOO not supported for current URL./AH00135: Invalid method in request |
Apache | メソッド名の綴り違い・クライアントの不具合。送る側を直す |
501 Unsupported method ('POST') |
Python http.server | 確認用サーバーに POST。アプリのサーバーを使う |
{"detail":"Method Not Allowed"}・allow: GET |
FastAPI | Allow にあるメソッドで送る。HEAD が要るなら api_route に足す |
Cannot POST /items(404) |
Express | POST のルートが無い。ルートを足すか、405のミドルウェアで案内 |
Response to preflight request doesn't pass access control check |
Chrome のコンソール | OPTIONS が405。CORS のミドルウェアを入れる |
client sent unknown "Transfer-Encoding": "gzip"(501) |
nginx の error.log(info) | クライアント・中継が未対応の転送符号化を付けている。外す |
access forbidden by rule(403) |
nginx の error.log | limit_except で止めたメソッド。405ではなく403になる |
HTTP ERROR 405/HTTP ERROR 501 |
Chrome の画面 | 本文の無い応答。ネットワークのタブで Allow とサーバー名を見る |
ほかのステータスコードは関連記事「HTTPステータスコード 一覧|全コードの原因と対処・curl実例つき」で、認証と権限の401・403は関連記事「401と403の違い|Unauthorized・Forbiddenの原因と直し方」で扱っています。
よくある質問
Q. 405 Method Not Allowed とは何ですか? A. リクエストのメソッド(GET・POST など)をサーバーは知っているが、そのURL(リソース)では受け付けていない、という意味のステータスコードです。応答には、使えるメソッドを並べた Allow ヘッダーが付きます(RFC 9110 で必須)。
Q. 501 Not Implemented とは何ですか? A. リクエストを処理するのに必要な機能をサーバーが実装していない、という意味のサーバーエラーです。サーバーが知らないメソッドや、未対応の Transfer-Encoding を受け取ったときに返します。GET と HEAD に501を返してはいけません。
Q. 405と501はどう使い分けますか? A. メソッドを「知っているが、このURLでは使えない」なら405、「そもそも知らない・実装していない」なら501です。RFC 9110 の 9.1 は、未認識・未実装のメソッドには501、認識し実装しているが対象のリソースで許可していないメソッドには405を返す(SHOULD)としています。
Q. 405と404の違いは? A. 404はURLそのものが無い、405はURLはあるがメソッドが違う、です。Express の既定は、メソッドが違っても404(Cannot POST /items)を返すので、区別したいときは405を自分で返します。
Q. GET では開けるのに、フォームを送ると405になります。
A. 送り先(action)がHTMLなどの静的ファイルになっていることがほとんどです。nginx は静的ファイルへの POST に「405 Not Allowed」を返します。送り先をアプリのURLにするか、nginx の error_page 405 =200 $uri; で HTML を返します。
Q. python -m http.server に POST すると501になります。
A. http.server の既定のハンドラーは GET と HEAD しか持たず、それ以外は 501 Unsupported method になります。POST を受けるには do_POST を持つハンドラーを書くか、Flask・FastAPI などのアプリのサーバーを使います。
Q. CORS エラーと出ますが、サーバーのログには OPTIONS の405があります。 A. ブラウザのプリフライト(OPTIONS)に、サーバーが405を返しています。OPTIONS に自分で答えるのではなく、FastAPI の CORSMiddleware・Express の cors などの仕組みを入れて、allow_methods に本番のメソッドを含めます。
Q. Allow ヘッダーは必ず付けないといけませんか?
A. RFC 9110 は405の応答に Allow を生成しなければならない(MUST)としています。FastAPI・Flask・Django は自動で付け、Apache も付けます。nginx の静的ファイルの405と、自作のコードで send_error(405) しただけの応答には付かないので、自分で足します。
Q. nginx の limit_except でメソッドを制限したら、405ではなく403になりました。
A. limit_except の中身は deny などのアクセス制限なので、結果は403(access forbidden by rule)です。Apache の <LimitExcept> も同じく403です。405を返したいときは、アプリ側でルートを定義して返します。
Q. 「未実装の機能」のエンドポイントには501を返すべきですか? A. 一般的には返しません。501は「サーバーがそのメソッド・機能に対応していない」という HTTP の層の意味で、Web サーバーやフレームワークが返すものです。作っていない機能は、URL ごと無いので404にするか、仕様として用意しないのが普通です。
Q. WordPress の投稿で501が出ます。 A. レンタルサーバーの WAF が、投稿の内容(コマンドに関する語など)を検知して止めている例が多く報告されています。エックスサーバーは公式のお知らせで、メールフォームの「WAF有効時の501エラー表示」を修正したと案内しています。WAF を一時的に無効化して再現するかを確かめ、確かめたら戻します。
Q. 405や501はキャッシュされますか? A. RFC 9110 は、405も501も「特に指定が無ければキャッシュされ得る」としています。直したあとも405が出続けるときは、ブラウザや CDN のキャッシュを疑い、Cache-Control を確かめます。
まとめ
- 405は「メソッドは知っているが、このURLでは受け付けない」、501は「そのメソッド・機能をサーバーが実装していない」。405には Allow ヘッダーが必須(RFC 9110 15.5.6・10.2.1)。
- GET で開けるのに POST で405になる典型は、静的ファイルへの POST・フォームの action の誤り・CORS のプリフライト OPTIONS。nginx は静的ファイルへの POST に「405 Not Allowed」(Allow なし)、Apache は POST を 200・PUT を405・未知のメソッドを501と返し分けた。
- Python の http.server は do_POST が無いメソッドをすべて501にする。自作するなら「URL なし→404、メソッド違い→405+Allow、未定義→501」の順。
- FastAPI・Flask・Django は405と Allow を自動で返し、Express の既定は404「Cannot POST」。FastAPI は HEAD を自動では足さない。Node.js は未知のメソッドを400にする。
- nginx の limit_except と Apache の LimitExcept は405ではなく403。ALB は TRACE に405・未対応の Transfer-Encoding に501、レンタルサーバーの WAF が501を返すことは公式ページの範囲で確かめた。
参考・出典
確認日はいずれも 2026年10月29日です。
- IETF「RFC 9110 HTTP Semantics」9.1 Overview(メソッド)・10.2.1 Allow・15.5.6 405 Method Not Allowed・15.6.2 501 Not Implemented:https://www.rfc-editor.org/rfc/rfc9110
- IETF「RFC 9112 HTTP/1.1」3 Request Line・6.1 Transfer-Encoding(501 を返す場面):https://www.rfc-editor.org/rfc/rfc9112
- MDN「405 Method Not Allowed」:https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Status/405
- MDN「501 Not Implemented」:https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Status/501
- MDN「Allow」:https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Allow
- nginx「Module ngx_http_core_module」limit_except・error_page:https://nginx.org/en/docs/http/ngx_http_core_module.html
- Apache「core - Apache HTTP Server」Limit・LimitExcept・TraceEnable:https://httpd.apache.org/docs/2.4/mod/core.html
- Python「http.server --- HTTP サーバー」:https://docs.python.org/ja/3/library/http.server.html
- FastAPI「CORS (Cross-Origin Resource Sharing)」:https://fastapi.tiangolo.com/tutorial/cors/
- Express「Routing」app.route・app.all:https://expressjs.com/en/guide/routing.html
- AWS「Troubleshoot your Application Load Balancers」HTTP 405・HTTP 501:https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-troubleshooting.html
- エックスサーバー「WAF設定」:https://www.xserver.ne.jp/manual/man_server_waf.php
- エックスサーバー「お知らせ:メールフォーム 最新版(1.3.1)の提供について」:https://www.xserver.ne.jp/news_detail.php?view_id=13282
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「405 Method Not Allowedと501の違い|Allowと直し方・原文」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。