Web サービスを使っているとレスポンスとしてリダイレクトを返すことはちょくちょくあると思います。このとき 301
/ 302
のようなステータスコードを返すとたとえ POST リクエストであっても GET に強制変更されてリダイレクトされてしまいます。通常はこの挙動でほぼ問題ないのですが、ごく稀にリダイレクト時にも HTTP Method を維持したいケースもあるでしょう。
TL;DR
307
/ 308
を返せば OK!
ASP.NET Core MVC だと
下記のような感じで preserveMethod: true
とするのがポイントです。
[HttpPost] public IActionResult DoSomething() { const string url = "https://example.com"; return new RedirectResult(url, permanent: false, preserveMethod: true); }
HttpClient の実装を覗いてみる
HttpClient
には Auto-Redirect という仕様があり、以下のステータスコードを受けた場合に Location ヘッダーで指定された URL に自動リダイレクトします。
300
: MultipleChoices301
: Moved302
: Found303
: SeeOther307
: TemporaryRedirect308
: PermanentRedirect
このうち、300
/ 301
/ 302
/ 303
は POST リクエストを GET に強制変更してアクセスするようになっています。なので 307
/ 308
だと大丈夫。なるほどねー。
この Auto-Redirect は明示的に Opt-out しない限り既定で有効です。無効化したい場合は以下のようにしましょう。
var handler = new HttpClientHandler{ AllowAutoRedirect = false }; var client = new HttpClient(handler); var response = await client.GetAsync(url);
おまけ
BuriKaigi 2021 のライブコーディング対決のオセロ勝負ではこの挙動を利用しました。(端折って説明すると) 4 人でオセロの Web API を作り、誰の API が強いのかを競うものです。
ここで僕は自分でオセロのアルゴリズムを実装することなく、他メンバーが作った強い API に相乗りするチートをしました。その際に Auto-Redirect の仕組みを利用したんですねー(セコイ