xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

POST を維持したままリダイレクトする

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 : MultipleChoices
  • 301 : Moved
  • 302 : Found
  • 303 : SeeOther
  • 307 : TemporaryRedirect
  • 308 : 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 の仕組みを利用したんですねー(セコイ