代码之家  ›  专栏  ›  技术社区  ›  Paulo Coghi

如何发送HTTP响应代码?

  •  207
  • Paulo Coghi  · 技术社区  · 14 年前

    我有一个PHP脚本,需要用HTTP响应代码(状态代码)做出响应,比如HTTP200OK,或者一些4xx或5xx代码。

    如何在PHP中执行此操作?

    8 回复  |  直到 6 年前
        1
  •  394
  •   dualed    12 年前

    我刚发现这个问题,觉得需要更全面的答案:

    至于 PHP 5.4 实现这一点有三种方法:

    自行组装响应代码(php>=4.0)

    这个 header() 函数有一个特殊的用例,用于检测HTTP响应行,并允许您将其替换为自定义的响应行。

    header("HTTP/1.1 200 OK");
    

    但是,这需要对(快速)CGI PHP进行特殊处理:

    $sapi_type = php_sapi_name();
    if (substr($sapi_type, 0, 3) == 'cgi')
        header("Status: 404 Not Found");
    else
        header("HTTP/1.1 404 Not Found");
    

    注: 根据 HTTP RFC , the 原因短语 可以是任何自定义字符串(符合标准),但为了客户端兼容性,我 建议在此处放置随机字符串。

    注: php_sapi_name() 要求 PHP4.0.1

    头函数的第三个参数(php>=4.3)

    在使用第一个变体时,显然存在一些问题。我认为其中最大的一点是,它部分是由PHP或Web服务器解析的,并且文档记录得很差。

    自4.3以来, header 函数有第三个参数,允许您稍微轻松地设置响应代码,但使用它需要第一个参数是非空字符串。以下是两个选项:

    header(':', true, 404);
    header('X-PHP-Response-Code: 404', true, 404);
    

    我推荐第二个 . 第一 在我测试过的所有浏览器上都可以使用,但是一些次要的浏览器或网络爬虫可能会遇到标题行只包含冒号的问题。第2个中的标题字段名。变体当然不是以任何方式标准化的,可以修改,我只是选择了一个有希望的描述性名称。

    http_response_code函数(php>=5.4)

    这个 http_response_code() 函数是在php 5.4中引入的,它使 很多 更容易的。

    http_response_code(404);
    

    这就是全部。

    兼容性

    当我需要低于5.4的兼容性,但需要“新”的功能时,我准备了一个函数。 http_response_code 功能。我相信php 4.3有足够的向后兼容性,但你永远不会知道…

    // For 4.3.0 <= PHP <= 5.4.0
    if (!function_exists('http_response_code'))
    {
        function http_response_code($newcode = NULL)
        {
            static $code = 200;
            if($newcode !== NULL)
            {
                header('X-PHP-Response-Code: '.$newcode, true, $newcode);
                if(!headers_sent())
                    $code = $newcode;
            }       
            return $code;
        }
    }
    
        2
  •  32
  •   halfer    9 年前

    不幸的是,我发现@dualed提供的解决方案有很多缺陷。

    1. 使用 substr($sapi_type, 0, 3) == 'cgi' 不足以检测快速的CGI。使用php-fpm fastcgi process manager时, php_sapi_name() 返回fpm而不是cgi

    2. fasctcgi和php fpm公开了@josh提到的另一个错误-使用 header('X-PHP-Response-Code: 404', true, 404); 在php-fpm(fastcgi)下工作正常吗?

    3. header("HTTP/1.1 404 Not Found"); 如果协议不是http/1.1(即“http/1.0”),则可能会失败。必须使用以下方法检测当前协议 $_SERVER['SERVER_PROTOCOL'] (从php 4.1.0开始提供

    4. 呼叫时至少有2个案例 http_response_code() 导致意外行为:

      • 当PHP遇到它不理解的HTTP响应代码时,PHP将用它从同一组中知道的代码替换该代码。例如,“521 Web服务器关闭”替换为“500内部服务器错误”。其他组2xx、3xx、4xx的许多异常响应代码都是通过这种方式处理的。
      • 在具有php fpm和nginx http_response_code()函数的服务器上,可以按预期更改代码,但不能更改消息。例如,这可能会导致一个奇怪的“404 OK”头段。这个问题在PHP网站上也被用户评论提到。 http://www.php.net/manual/en/function.http-response-code.php#112423

    这里有完整的HTTP响应状态代码列表供您参考(此列表包括来自IETF Internet标准以及其他IETF RFC的代码)。php http_response_code函数目前不支持其中的许多功能): http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

    您可以通过调用以下命令轻松测试此Bug:

    http_response_code(521);
    

    服务器将发送“500内部服务器错误”HTTP响应代码,如果您有一个自定义客户端应用程序调用您的服务器,并期望一些额外的HTTP代码,则会导致意外错误。


    我的解决方案(对于4.1.0以后的所有PHP版本):

    $httpStatusCode = 521;
    $httpStatusMsg  = 'Web server is down';
    $phpSapiName    = substr(php_sapi_name(), 0, 3);
    if ($phpSapiName == 'cgi' || $phpSapiName == 'fpm') {
        header('Status: '.$httpStatusCode.' '.$httpStatusMsg);
    } else {
        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
        header($protocol.' '.$httpStatusCode.' '.$httpStatusMsg);
    }
    

    结论

    http_response_code()实现不支持所有http响应代码,可能会用同一组中的另一个代码覆盖指定的http响应代码。

    新的http_response_code()函数并不能解决所有涉及的问题,但会使引入新bug的情况变得更糟。

    @dualed提供的“兼容性”解决方案无法按预期工作,至少在php-fpm下是这样。

    @dualed提供的其他解决方案也有各种错误。快速CGI检测不处理php-fpm。必须检测当前协议。

    感谢所有测试和评论。

        3
  •  11
  •   Seyed Ali Roshan    8 年前

    从php 5.4开始,您可以使用 http_response_code() 用于获取和设置标题状态代码。

    这里有一个例子:

    <?php
    
    // Get the current response code and set a new one
    var_dump(http_response_code(404));
    
    // Get the new response code
    var_dump(http_response_code());
    ?>
    

    下面是php.net中此函数的文档:

    http_response_code

        4
  •  7
  •   sparkey0    14 年前

    在主体的任何输出之前添加这一行,以防不使用输出缓冲。

    header("HTTP/1.1 200 OK");
    

    将消息部分(“OK”)替换为适当的消息,将状态代码替换为适当的代码(404、501等)。

        5
  •  6
  •   jaggedsoft    11 年前

    如果你在这里是因为WordPress在加载环境时给出了404,这应该可以解决问题:

    define('WP_USE_THEMES', false);
    require('../wp-blog-header.php');
    status_header( 200 );
    //$wp_query->is_404=false; // if necessary
    

    问题是由于它发送了一个状态:404 Not Found头。你必须超越它。 这也适用于:

    define('WP_USE_THEMES', false);
    require('../wp-blog-header.php');
    header("HTTP/1.1 200 OK");
    header("Status: 200 All rosy");
    
        6
  •  5
  •   Quentin    14 年前

    header 功能。本节中有一个关于它所采用的第一个参数的示例。

        7
  •  1
  •   Chris Forrence Shreya Gupta    8 年前
    header("HTTP/1.1 200 OK");
    http_response_code(201);
    

    HTTP响应代码(200);由于测试警报404而不起作用 https://developers.google.com/speed/pagespeed/insights/

        8
  •  0
  •   סטנלי גרונן Abhishek Singh    6 年前

    我们可以通过两种不同的环境从HTTP响应代码中获得不同的返回值:

    1. Web服务器环境
    2. CLI环境

    在Web服务器环境中,如果提供了响应代码或没有提供任何响应代码,则返回以前的响应代码,然后将打印当前值。默认值为200(确定)。

    在cli环境中,如果提供了响应代码,则返回true;如果不提供任何响应代码,则返回false。

    响应代码返回值的Web服务器环境示例:

    var_dump(http_respone_code(500)); // int(200)
    var_dump(http_response_code()); // int(500)
    

    响应代码返回值的cli环境示例:

    var_dump(http_response_code()); // bool(false)
    var_dump(http_response_code(501)); // bool(true)
    var_dump(http_response_code()); // int(501)