Использование заголовка в PHP - PullRequest
4 голосов
/ 04 января 2010

Довольно простой вопрос: какой из этих двух вызовов заголовка PHP (версия 5+) является «лучшим»?

header('Not Modified', true, 304);
header('HTTP/1.1 304 Not Modified');

Я уверен, что первый является наиболее поливалентным, но просто любопытно, если бы PHP "исправил" второй, если под HTTP 1.0 ...

Спасибо!

Редактировать: Один из этих заголовков приводит к сбою PHP на моем веб-хосте. Дополнительный вопрос по адресу: PHP header () вызывает "сбойный" скрипт с ошибкой HTTP 500

Ответы [ 6 ]

8 голосов
/ 04 января 2010

Я бы использовал это:

header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified', true, 304);

$_SERVER['SERVER_PROTOCOL'] содержит протокол, используемый в запросе, например HTTP/1.0 или HTTP/1.1.


Редактировать Я должен признать, что мое предложение бессмысленно. После нескольких тестов я заметил, что если первым параметром является действительная строка состояния HTTP , PHP будет использовать эту строку состояния независимо от того, какой второй код состояния был задан с третьим параметром. И второй параметр (документация называет его replace ) также бесполезен, так как не может быть нескольких строк состояния.

Таким образом, второй и третий параметры в этом вызове просто избыточны:

header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified', true, 304);

Используйте только это вместо:

header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified');
4 голосов
/ 04 января 2010

В поведении первого вызова заголовка есть две вещи, на которые стоит обратить внимание:

  • Если вы укажете третий аргумент, PHP проигнорирует первый строковый аргумент и отправит правильный ответ для данного числа. Это может сделать первый метод менее подверженным ошибкам программиста.
  • PHP, кажется, отвечает HTTP / 1.1 ответом, даже когда запрос был сделан с HTTP / 1.0
2 голосов
/ 25 января 2012

Для дальнейшего использования функция http_response_code () появится в версии 5.4:

http://www.php.net/manual/en/function.http-response-code.php

Альтернатива:

if (!function_exists('http_response_code')) {
    function http_response_code($code = NULL) {

        if ($code !== NULL) {

            switch ($code) {
                case 100: $text = 'Continue'; break;
                case 101: $text = 'Switching Protocols'; break;
                case 200: $text = 'OK'; break;
                case 201: $text = 'Created'; break;
                case 202: $text = 'Accepted'; break;
                case 203: $text = 'Non-Authoritative Information'; break;
                case 204: $text = 'No Content'; break;
                case 205: $text = 'Reset Content'; break;
                case 206: $text = 'Partial Content'; break;
                case 300: $text = 'Multiple Choices'; break;
                case 301: $text = 'Moved Permanently'; break;
                case 302: $text = 'Moved Temporarily'; break;
                case 303: $text = 'See Other'; break;
                case 304: $text = 'Not Modified'; break;
                case 305: $text = 'Use Proxy'; break;
                case 400: $text = 'Bad Request'; break;
                case 401: $text = 'Unauthorized'; break;
                case 402: $text = 'Payment Required'; break;
                case 403: $text = 'Forbidden'; break;
                case 404: $text = 'Not Found'; break;
                case 405: $text = 'Method Not Allowed'; break;
                case 406: $text = 'Not Acceptable'; break;
                case 407: $text = 'Proxy Authentication Required'; break;
                case 408: $text = 'Request Time-out'; break;
                case 409: $text = 'Conflict'; break;
                case 410: $text = 'Gone'; break;
                case 411: $text = 'Length Required'; break;
                case 412: $text = 'Precondition Failed'; break;
                case 413: $text = 'Request Entity Too Large'; break;
                case 414: $text = 'Request-URI Too Large'; break;
                case 415: $text = 'Unsupported Media Type'; break;
                case 500: $text = 'Internal Server Error'; break;
                case 501: $text = 'Not Implemented'; break;
                case 502: $text = 'Bad Gateway'; break;
                case 503: $text = 'Service Unavailable'; break;
                case 504: $text = 'Gateway Time-out'; break;
                case 505: $text = 'HTTP Version not supported'; break;
                default:
                    exit('Unknown http status code "' . htmlentities($code) . '"');
                break;
            }

            $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');

            header($protocol . ' ' . $code . ' ' . $text);

            $GLOBALS['http_response_code'] = $code;

        } else {

            $code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);

        }

        return $code;

    }
}

В этом примере я использую $ GLOBALS, но вы можете использовать любой механизм хранения, который вам нравится ... Я не думаю, что есть способ вернуть текущий код состояния:

https://bugs.php.net/bug.php?id=52555

Для справки коды ошибок, которые я получил из исходного кода PHP:

http://lxr.php.net/opengrok/xref/PHP_5_4/sapi/cgi/cgi_main.c#354

И как отправляется текущий заголовок http с используемыми переменными:

http://lxr.php.net/opengrok/xref/PHP_5_4/main/SAPI.c#856

2 голосов
/ 04 января 2010

Обычно я бы пошел со вторым примером - однако, когда мы недавно тестировали приложение с помощью apachebench, мы часто замечали зависание.

После отладки было выявлено, что заголовок в этом стиле:

header('HTTP/1.1 304 Not Modified')

Был виновником (Да, я понятия не имею) и после изменения на,

header('Not Modified', true, 304);

Хотите верьте, хотите нет, ab начал работать. Очень странно, но есть над чем подумать. Я, вероятно, буду использовать второй метод в будущем.

2 голосов
/ 04 января 2010

Я бы пошел со вторым, так как аргумент кода ответа http поддерживается только> = PHP 4.3.0 (что может повлиять на переносимость кода).

Я делал это много раз и не сталкивался ни с одним клиентом, который не поддерживает HTTP / 1.1, поэтому, если у вас нет особого случая, я не думаю, что это когда-нибудь станет проблемой.

1 голос
/ 04 января 2010

Я думаю, что ответ Гамбо - самый разумный на данный момент. Однако попробуйте это:

<?php
header('Gobbledy Gook', true, 304);
?>

Если первая строка не является правильным заголовком, она отбрасывается. Если iy выглядит как действительный заголовок, он добавляется к заголовкам - попробуйте это:

<?php
header('Cache-Control: max-age=10', true, 304);
?>

Руководство для header () и обратите внимание на особые случаи - в общем, я думаю, что не стоит полагаться на такую ​​встроенную эвристику.

Тем не менее, я предполагаю, что вы действительно заинтересованы в том, чтобы контент хорошо кэшировался прокси / браузерами. В большинстве случаев задержка является гораздо большей проблемой, чем пропускная способность. Далее рассмотрим, как ведет себя браузер, когда кэшированный контент устарел - в отсутствие обновленной информации о кэшировании он продолжает повторять запросы к серверу, чтобы проверить, не устарел ли контент.

т.е. в большинстве случаев игнорирование условной части запросов (или даже лучшее их удаление на веб-сервере) фактически повышает производительность.

...