【问题标题】:401 redirect magically results in a 302 redirect401 重定向神奇地导致 302 重定向
【发布时间】:2012-11-09 03:41:27
【问题描述】:

我正在使用Redirect 类将未登录的用户发送到登录页面,并带有 401 状态码:

return Redirect::to('login', 401);

这会发送正确的位置标头,但状态代码设置为 302


我一直追踪到 Response 的基类

laravel/vendor/Symfony/Component/HttpFoundation/Response.php

它正在调用:

$this->setStatusCode($status);

使用正确的 401 代码。


我也尝试过转储对象:

var_dump( Redirect::to('login', 401)->foundation );

我可以看到受保护的statusCode 属性已正确设置为 401


不过,生成的响应的 HTTP 状态代码设置为 302

什么给了?是不是我用错了?


P.S.我也posted this on Laravel's forums,无济于事。

【问题讨论】:

  • 您正在开发什么操作系统(和服务器)?
  • 在此重定向之后是否还有其他不明显的重定向? 401 可以工作,然后 302 重定向在此之后跳入并进行重定向......在这里抓住稻草

标签: php redirect header laravel


【解决方案1】:

这不是因为 laravel,你可以只用 (php 5.4 in windows) 重现这个:

<?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);
        }
    }

如你所见,当你用"Location"header()时,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,浏览器也不会跟随重定向。

【讨论】:

  • +1 谢谢。有没有其他方法可以解决这个问题?我希望未经授权的用户被重定向到登录页面,但我还需要我的 AJAX 请求来了解用户何时注销(我使用的方法类似于此处Ben Nadel 概述的方法)。
  • @JosephSilber jQuery 在请求上添加 X-Requested-With 标头,让您知道它是使用 ajax 制作的。然后,您可以为 ajax 设置 401 状态,并为常规请求设置重定向状态
  • 我想过这个,但在某处读到他们打算放弃它。现在找不到来源。你能确认一下吗?
  • @JosephSilber 无法通过谷歌搜索找到任何相关信息,但这似乎很疯狂。所有/大多数 ajax 库都带有该标头,它非常有用,因为 ajax 请求的工作方式非常不同,例如在响应 ajax 请求时重定向没有意义。
  • 好吧,那我一定是在过去的某一时刻产生了幻觉。无论如何,我采用了这个解决方案,它完美无缺。再次感谢。
【解决方案2】:

浏览器不会让你这样做;您不能使用 401 重定向。

【讨论】:

    【解决方案3】:

    我更进一步...直到public function sendHeaders() in laravel/vendor/Symfony/Component/HttpFoundation/Response.php...它生成最终状态标题

       // status
        Header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
    

    ...当然,它仍然是 401。

    然后我恍然大悟。 您不能使用 401 重定向,这是一个 ClientError。

    (同样Response.php 文件中的isRedirect 测试也会失败。mod_php 会在您发送Location 后立即为您修复为 302(因为默认状态为 200,所以它需要更新。PHP不会检查它是否已经更新为其他东西。

    【讨论】:

    • +1 表示一路走下这个兔子洞。谢谢。
    【解决方案4】:

    正如其他人所指出的,没有 401 重定向这样的东西。我迷上这个的原因是因为I need non-AJAX users to be redirected,但是AJAX requests should get a 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 1970-01-01
      • 2016-07-19
      相关资源
      最近更新 更多