Я использую класс Redirect
для отправки невостребованных пользователей на страницу входа с кодом состояния 401 :
return Redirect::to('login', 401);
Это отправляет правильный заголовок местоположения, но для кода состояния установлено значение 302 .
Я проследил его до базового класса Response
в
Laravel / продавец / Symfony / Компонент / HttpFoundation / Response.php
и он звонит:
$this->setStatusCode($status);
с правильным кодом 401 .
Я также попытался сбросить объект:
var_dump( Redirect::to('login', 401)->foundation );
и я вижу, что свойство statusCode
правильно установлено в 401 .
Тем не менее, код статуса HTTP сгенерированного ответа установлен в 302 .
Что дает? Я использую это неправильно?
PS Я также разместил это на форумах Laravel , но безрезультатно.
Это не из-за laravel, вы можете воспроизвести это просто (php 5.4 в окнах):
<?php header("HTTP/1.1 401 Unauthorized"); header("Location: http://www.google.com");
Похоже, php устанавливает значение 302:
$ php-cgi "test.php" Status: 302 Moved Temporarily Location: http://www.google.com Content-type: text/html; charset=UTF-8
В исходном коде PHP main / SAPI.C:
} else if (!STRCASECMP(header_line, "Location")) { if ((SG(sapi_headers).http_response_code < 300 || SG(sapi_headers).http_response_code > 307) && SG(sapi_headers).http_response_code != 201) { /* Return a Found Redirect if one is not already specified */ if (http_response_code) { /* user specified redirect code */ sapi_update_response_code(http_response_code TSRMLS_CC); } else if (SG(request_info).proto_num > 1000 && SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD") && strcmp(SG(request_info).request_method, "GET")) { sapi_update_response_code(303 TSRMLS_CC); } else { sapi_update_response_code(302 TSRMLS_CC); } }
Как вы можете видеть, когда вы делаете header()
с "Location"
, код статуса http изменяется до 302
Вы можете заставить его работать, если вы сделаете это наоборот:
<?php header("Location: http://www.google.com"); header("HTTP/1.1 401 Unauthorized");
Это даст:
$ php-cgi "test.php" Status: 401 Unauthorized Location: http://www.google.com Content-type: text/html; charset=UTF-8
Но laravel устанавливает местоположение после установки статуса, поэтому статус все равно установлен на 302. Но это спорный вопрос, даже если вы успешно установили статус 401 с заголовком местоположения, перенаправление не сопровождается браузерами.
Браузеры не позволят вам это сделать; Вы не можете перенаправить с помощью 401.
Я следил за ним еще дальше … до public function sendHeaders()
в laravel/vendor/Symfony/Component/HttpFoundation/Response.php
… где он генерирует заголовок окончательного состояния
// status Header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
… и это было все еще 401, конечно.
Тогда мне стало понятно. Вы не можете перенаправить с помощью 401 , который является ClientError.
(Это также провалит тест isRedirect
указанный в том же файле Response.php
. mod_php
исправит его для вас до 302, как только вы отправите Location
(потому что по умолчанию статус 200, поэтому его необходимо обновить. PHP doesn ' t проверить, было ли оно уже обновлено на что-то еще).
Как отмечают другие, нет такой вещи, как переадресация 401. Причина, по которой я попал в это, заключалась в том, что мне нужно перенаправить пользователей, не являющихся AJAX , но запросы AJAX должны получить 401 .
Если вы оказались в подобной ситуации, вот что я в итоге использовал:
return Request::ajax() ? Response::make('', 401, array('HTTP/1.1 401 Unauthorized')) : Redirect::to('login', 302);
Это использует методы Laravel для обработки заголовков.
Если вы используете ванильный PHP, используйте это:
$is_ajax_request = ! empty( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'; $is_ajax_request ? header('HTTP/1.1 401 Unauthorized') : header('Location: http://site.com/login'); exit;