コードロード

エラー討伐

【PHP】ある特定のAPIへリクエストすると勝手にリダイレクトされる

結論

リダイレクト時のステータスコード301 ではなく 302 を使う!

※もしくは明示的に指定しなければデフォルトで302になる

前提

一般ユーザーAでログインしているときに /user へリクエストすると、制限された情報を返すAPIがある。

一方、Adminユーザーでログインしているときに /user へリクエストすると、API側でAdminであれば /admin/user へリダイレクトさせる処理があった。

このときにリダイレクト処理を下記のようにしてしまっていた。

<?php

if ($user_id === ADMIN_USER_ID) {
    header("Location: /admin/user", true, 301);
    exit;
}

再現手順

  1. Adminユーザーでログインして /user へリクエストすると、API側で /admin/user にリダイレクトされる。(想定された挙動)
  2. Adminユーザーからログアウト
  3. 一般ユーザーAでログイン
  4. /user へリクエストすると、 /admin/user へなぜかリダイレクトされる。
  5. /admin/user 自体はAdminユーザーでないと認可していないので、 ステータスコード403 で返ってくる。(想定されていない挙動)
  6. 想定されたレスポンスが返ってこないのでエラーが出る。

原因

301 でリダイレクトさせるとブラウザ側でキャッシュしてしまうことが原因っぽい。

ちゃんとドキュメントに書いてあった。

www.php.net

A quick way to make redirects permanent or temporary is to make use of the $http_response_code parameter in header().

<?php

// 301 Moved Permanently

header("Location: /foo.php",TRUE,301);

// 302 Found

header("Location: /foo.php",TRUE,302);

header("Location: /foo.php");

// 303 See Other

header("Location: /foo.php",TRUE,303);

// 307 Temporary Redirect

header("Location: /foo.php",TRUE,307);

?>

The HTTP status code changes the way browsers and robots handle redirects, so if you are using header(Location:) it's a good idea to set the status code at the same time.  Browsers typically re-request a 307 page every time, cache a 302 page for the session, and cache a 301 page for longer, or even indefinitely.  Search engines typically transfer "page rank" to the new location for 301 redirects, but not for 302, 303 or 307. If the status code is not specified, header('Location:') defaults to 302.

参考

PHPで301リダイレクトする時の注意点。ブラウザのキャッシュで意図しないページにリダイレクトされる