Spring BootやSpring MVCを利用してWebアプリケーションやAPIを開発している際、ブラウザのコンソールやサーバーのログにorg.springframework.web.HttpRequestMethodNotSupportedExceptionというエラーが表示されることがあります。
この例外は、クライアントから送信されたHTTPリクエストメソッドが、サーバー側で定義されたエンドポイントの許容メソッドと一致しない場合に発生します。
開発者にとって非常に遭遇頻度の高いエラーの一つですが、その発生原因は単純な実装ミスから設定の不備まで多岐にわたります。
本記事では、この例外の根本的なメカニズムから、具体的な発生シナリオ、そしてプロフェッショナルな現場で推奨される解決策までを詳しく解説します。
HttpRequestMethodNotSupportedExceptionとは何か
org.springframework.web.HttpRequestMethodNotSupportedExceptionは、Spring FrameworkにおけるWeb層の例外クラスの一つです。
クライアント(ブラウザや外部システム)が特定のURLに対してリクエストを送った際、そのURLに対してサポートされていないHTTPメソッド(GET, POST, PUT, DELETEなど)が使用されたことを通知するためにスローされます。
この例外が発生すると、Spring MVCはデフォルトでHTTPステータスコード405 Method Not Allowedをクライアントに返します。
HTTPプロトコルの仕様上、405エラーを返す際には、そのリソースで利用可能なメソッドをレスポンスヘッダーのAllowフィールドに含めることが推奨されています。
Springはこの仕様を適切に処理し、どのメソッドが本来許可されているのかを自動的に判断してレスポンスを生成します。
DispatcherServletによるハンドリング
Spring MVCの動作において、すべてのリクエストはまずDispatcherServletによって受け取られます。
このサーブレットは、登録されているHandlerMapping(主にRequestMappingHandlerMapping)を参照して、リクエストURLとメソッドに合致するコントローラーのメソッドを探します。
- リクエストが特定のパス(例:
/api/user)に届く。 - そのパスに対応するメソッドが定義されているかを確認する。
- パスは一致するが、メソッド(例:POST)が定義されていない場合、この例外がスローされる。
このプロセスを理解しておくことは、複雑なルーティング設定を行っている際のデバッグにおいて非常に重要です。
主な発生原因とシナリオ
この例外が発生する主な原因は、大きく分けて「実装の不一致」「設定の不備」「フロントエンドの挙動」の3点に集約されます。
コントローラー側の定義ミス
最も一般的な原因は、コントローラークラスでの@RequestMappingや、その派生アノテーション(@GetMapping, @PostMappingなど)の設定ミスです。
例えば、データの登録処理を意図してメソッドを作成したものの、誤って@GetMappingを付与してしまい、クライアントからのPOSTリクエストを拒否してしまうケースです。
また、共通のパスをクラスレベルの@RequestMappingで定義している場合、配下のメソッドすべてに適用される条件を正しく把握できていないことも原因となり得ます。
フロントエンド(クライアント側)の呼び出しミス
JavaScriptのfetch APIやaxios、またはHTMLのformタグを利用してリクエストを送信する際、メソッドの指定が誤っている場合があります。
特に、HTMLのフォームはGETとPOSTしか標準でサポートしていないため、PUTやDELETEを使用しようとしてフィルター設定が漏れていると、意図しないメソッドで送信され、結果としてサーバー側で拒否されることになります。
Spring Securityの影響
Spring Securityを導入しているプロジェクトでは、CSRF(Cross-Site Request Forgery)対策が有効になっていることが一般的です。
POSTやPUTなどの状態を変更するリクエストにおいて、適切なCSRFトークンが含まれていない場合、Spring Securityはリクエストを拒否します。
この際、エラーハンドリングの設定によっては、本来のアクセス拒否(403)ではなく、メソッド不一致(405)のような挙動として表面化することが稀にあります。
異常系の再現とコード例
まずは、意図的にこの例外を発生させるコードを確認しましょう。
以下の例では、GETメソッドのみを許可しているエンドポイントに対してPOSTリクエストを送信するシチュエーションを想定しています。
エラーが発生するソースコード
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
// GETメソッドのみを許可するエンドポイント
@GetMapping("/api/hello")
public String sayHello() {
return "Hello, Spring Boot!";
}
}
このコントローラーに対して、curlコマンドを使用してPOSTリクエストを送信してみます。
curl -X POST http://localhost:8080/api/hello
実行結果とログ出力
サーバー側のコンソールには、以下のようなスタックトレースの一部が出力されます。
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]
また、クライアント(curl)に返されるレスポンスボディ(デフォルトのWhiteLabel Error Pageの場合)は以下のようになります。
{
"timestamp": "2026-03-20T10:00:00.000+00:00",
"status": 405,
"error": "Method Not Allowed",
"message": "Method 'POST' is not supported.",
"path": "/api/hello"
}
この結果からわかる通り、Springは「どのパスで」「どのメソッドが」拒否されたのかを明確に示してくれます。
HttpRequestMethodNotSupportedExceptionの対処法
この例外を解決するためのアプローチを、状況別に整理して解説します。
1. アノテーションの確認と修正
最も基本的な対処法は、コントローラーの定義をクライアントの要求に合わせることです。
もしPOSTリクエストを受け付ける必要があるなら、@PostMappingを使用するか、@RequestMappingに複数のメソッドを指定します。
@RestController
@RequestMapping("/api/data")
public class DataController {
// GETとPOSTの両方をサポートする場合
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
public String handleData() {
return "Success";
}
// または個別のアノテーションを併記する(推奨)
@PostMapping("/update")
public String updateData() {
return "Updated";
}
}
最近のSpring開発では、可読性の観点から@GetMappingや@PostMappingといった専用アノテーションを使用することが推奨されています。
2. クライアント側の実装修正
サーバー側の定義が正しい場合、クライアント側のコードを見直します。
特にJavaScriptからAPIを叩く場合、メソッド名がタイポ(例:PSTなど)になっていないか、あるいは小文字で記述されていないかを確認してください。
HTTPメソッドは大文字が基本です。
また、ブラウザによるプリフライトリクエスト(OPTIONSメソッド)が原因でエラーが発生している可能性もあります。
CORS(Cross-Origin Resource Sharing)の設定が不適切だと、ブラウザが本番のリクエストを送る前に送信するOPTIONSリクエストが405で返され、結果としてAPI呼び出し全体が失敗します。
3. @ControllerAdviceによるグローバルな例外ハンドリング
本番環境のアプリケーションでは、デフォルトのWhiteLabel Error Pageを表示させるのではなく、独自のレスポンスフォーマットでエラーを返したい場合があります。
その場合、@ControllerAdviceを使用して例外をキャッチし、カスタマイズしたレスポンスを返却します。
package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<Object> handleMethodNotAllowed(HttpRequestMethodNotSupportedException ex) {
Map<String, Object> body = new HashMap<>();
body.put("status", HttpStatus.METHOD_NOT_ALLOWED.value());
body.put("error", "指定されたHTTPメソッドは許可されていません");
body.put("supported_methods", ex.getSupportedHttpMethods());
body.put("message", "リクエストされたメソッド: " + ex.getMethod());
// 405 Method Not Allowedを返す
return new ResponseEntity<>(body, HttpStatus.METHOD_NOT_ALLOWED);
}
}
この実装を行うことで、フロントエンドエンジニアに対して「どのメソッドを使えば良いか」を明確に伝えることができ、デバッグ効率が大幅に向上します。
高度なトピック:パスの重複と優先順位
複雑なアプリケーションでは、似たようなURLパスが複数定義されていることがあります。
| パス定義 | メソッド | 説明 |
|---|---|---|
/api/users/{id} | GET | ユーザー取得 |
/api/users/admin | POST | 管理者登録 |
この場合、クライアントがPOST /api/users/123を送ると、Springはまずパス変数のパターンにマッチするエンドポイントを探します。
もしパス変数のパターンには一致するが、そこがGETしか許可していない場合、他により適合するパスがあってもHttpRequestMethodNotSupportedExceptionをスローすることがあります。
パスの設計(ルーティング)の重複を避けることも、このエラーを未然に防ぐ重要な設計指針となります。
デバッグ時のチェックリスト
問題が発生した際、迅速に解決するためのチェックリストを以下に示します。
/api/user と /api/user/ は設定によっては別物として扱われ、片方がメソッド未定義となる場合があります。
URLの記述が一致しているか確認してください。
ブラウザのデベロッパーツール(Networkタブ)を開き、実際に送信されている Request Method が意図したものと一致しているか確認してください。
NginxやApacheなどのリバースプロキシを挟んでいる場合、PUTやDELETEなどの特定のメソッドがプロキシ層で制限・拒否されていないか確認が必要です。
HTMLフォームでPUTやDELETEを疑似的に実現したい場合、Springの HiddenHttpMethodFilter が正しく構成されているかを確認してください。
まとめ
org.springframework.web.HttpRequestMethodNotSupportedExceptionは、APIのインターフェース契約が守られていないことを示す、Web開発における基本的な警告です。
その解決策は、多くの場合においてコントローラーのアノテーション設定を見直すか、クライアントのリクエスト送信処理を修正するかのどちらかに集約されます。
しかし、大規模なシステムやセキュリティ要件が厳しいプロジェクトでは、CORS設定やCSRFフィルター、あるいはリバースプロキシの構成が複雑に絡み合うこともあります。
エラーが発生した際には、まずはスタックトレースから「どのメソッドが拒否されたのか」を正確に読み取り、本記事で紹介した@ControllerAdviceによるハンドリングなどを活用して、ユーザーや他の開発者にとって分かりやすいエラー情報を提示するように努めましょう。
適切なHTTPメソッドの運用は、RESTfulな美しいAPIデザインへの第一歩です。






