Responses
Обзор
Flight помогает генерировать часть заголовков ответа для вас, но вы контролируете большую часть того, что отправляете обратно пользователю. Большинство времени вы будете обращаться напрямую к объекту response()
, но Flight имеет некоторые вспомогательные методы для установки некоторых заголовков ответа за вас.
Понимание
После того как пользователь отправит свой запрос в ваше приложение, вам нужно сгенерировать правильный ответ для него. Они отправили вам информацию, такую как предпочитаемый язык, могут ли они обрабатывать определенные типы сжатия, их пользовательский агент и т.д., и после обработки всего этого пришло время отправить им правильный ответ. Это может быть установка заголовков, вывод тела HTML или JSON для них или перенаправление на страницу.
Базовое использование
Отправка тела ответа
Flight использует ob_start()
для буферизации вывода. Это означает, что вы можете использовать echo
или print
для отправки ответа пользователю, и Flight захватит его и отправит обратно пользователю с соответствующими заголовками.
// Это отправит "Hello, World!" в браузер пользователя
Flight::route('/', function() {
echo "Hello, World!";
});
// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hello, World!
В качестве альтернативы вы можете вызвать метод write()
для добавления в тело.
// Это отправит "Hello, World!" в браузер пользователя
Flight::route('/', function() {
// подробно, но иногда это необходимо
Flight::response()->write("Hello, World!");
// если вы хотите получить тело, которое вы установили на этом этапе
// вы можете сделать это так
$body = Flight::response()->getBody();
});
JSON
Flight предоставляет поддержку для отправки JSON и JSONP ответов. Чтобы отправить JSON-ответ, вы передаете некоторые данные для кодирования в JSON:
Flight::route('/@companyId/users', function(int $companyId) {
// каким-то образом извлеките своих пользователей из базы данных, например
$users = Flight::db()->fetchAll("SELECT id, first_name, last_name FROM users WHERE company_id = ?", [ $companyId ]);
Flight::json($users);
});
// [{"id":1,"first_name":"Bob","last_name":"Jones"}, /* больше пользователей */ ]
Примечание: По умолчанию Flight отправит заголовок
Content-Type: application/json
с ответом. Он также будет использовать флагиJSON_THROW_ON_ERROR
иJSON_UNESCAPED_SLASHES
при кодировании JSON.
JSON с кодом статуса
Вы также можете передать код статуса как второй аргумент:
Flight::json(['id' => 123], 201);
JSON с красивой печатью
Вы также можете передать аргумент в последнее положение для включения красивой печати:
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Изменение порядка аргументов JSON
Flight::json()
— это очень устаревший метод, но цель Flight — поддерживать обратную совместимость для проектов. На самом деле это очень просто, если вы хотите переделать порядок аргументов для использования более простого синтаксиса, вы можете просто переназначить метод JSON как любой другой метод Flight:
Flight::map('json', function($data, $code = 200, $options = 0) {
// теперь вам не нужно `true, 'utf-8'` при использовании метода json()!
Flight::_json($data, $code, true, 'utf-8', $options);
}
// И теперь это можно использовать так
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);
JSON и остановка выполнения
v3.10.0
Если вы хотите отправить JSON-ответ и остановить выполнение, вы можете использовать метод jsonHalt()
. Это полезно для случаев, когда вы проверяете, возможно, какой-то тип авторизации, и если пользователь не авторизован, вы можете сразу отправить JSON-ответ, очистить существующее содержимое тела и остановить выполнение.
Flight::route('/users', function() {
$authorized = someAuthorizationCheck();
// Проверьте, авторизован ли пользователь
if($authorized === false) {
Flight::jsonHalt(['error' => 'Unauthorized'], 401);
// нет выхода; здесь не нужно.
}
// Продолжите с остальной частью маршрута
});
До v3.10.0 вы бы сделали что-то вроде этого:
Flight::route('/users', function() {
$authorized = someAuthorizationCheck();
// Проверьте, авторизован ли пользователь
if($authorized === false) {
Flight::halt(401, json_encode(['error' => 'Unauthorized']));
}
// Продолжите с остальной частью маршрута
});
Очистка тела ответа
Если вы хотите очистить тело ответа, вы можете использовать метод clearBody
:
Flight::route('/', function() {
if($someCondition) {
Flight::response()->write("Hello, World!");
} else {
Flight::response()->clearBody();
}
});
Случай использования выше, вероятно, не распространен, однако он может быть более распространен, если это используется в middleware.
Выполнение обратного вызова на теле ответа
Вы можете выполнить обратный вызов на теле ответа, используя метод addResponseBodyCallback
:
Flight::route('/users', function() {
$db = Flight::db();
$users = $db->fetchAll("SELECT * FROM users");
Flight::render('users_table', ['users' => $users]);
});
// Это сожмет gzip все ответы для любого маршрута
Flight::response()->addResponseBodyCallback(function($body) {
return gzencode($body, 9);
});
Вы можете добавить несколько обратных вызовов, и они будут выполняться в порядке добавления. Поскольку это может принимать любой вызываемый, он может принимать массив класса [ $class, 'method' ]
, замыкание $strReplace = function($body) { str_replace('hi', 'there', $body); };
или имя функции 'minify'
, если у вас есть функция для минимизации вашего html-кода, например.
Примечание: Обратные вызовы маршрутов не будут работать, если вы используете опцию конфигурации flight.v2.output_buffering
.
Обратный вызов конкретного маршрута
Если вы хотите, чтобы это применялось только к конкретному маршруту, вы можете добавить обратный вызов в сам маршрут:
Flight::route('/users', function() {
$db = Flight::db();
$users = $db->fetchAll("SELECT * FROM users");
Flight::render('users_table', ['users' => $users]);
// Это сожмет gzip только ответ для этого маршрута
Flight::response()->addResponseBodyCallback(function($body) {
return gzencode($body, 9);
});
});
Опция Middleware
Вы также можете использовать middleware для применения обратного вызова ко всем маршрутам через middleware:
// MinifyMiddleware.php
class MinifyMiddleware {
public function before() {
// Примените обратный вызов здесь на объекте response().
Flight::response()->addResponseBodyCallback(function($body) {
return $this->minify($body);
});
}
protected function minify(string $body): string {
// минимизируйте тело каким-то образом
return $body;
}
}
// index.php
Flight::group('/users', function() {
Flight::route('', function() { /* ... */ });
Flight::route('/@id', function($id) { /* ... */ });
}, [ new MinifyMiddleware() ]);
Коды статуса
Вы можете установить код статуса ответа, используя метод status
:
Flight::route('/@id', function($id) {
if($id == 123) {
Flight::response()->status(200);
echo "Hello, World!";
} else {
Flight::response()->status(403);
echo "Forbidden";
}
});
Если вы хотите получить текущий код статуса, вы можете использовать метод status
без каких-либо аргументов:
Flight::response()->status(); // 200
Установка заголовка ответа
Вы можете установить заголовок, такой как тип содержимого ответа, используя метод header
:
// Это отправит "Hello, World!" в браузер пользователя в виде обычного текста
Flight::route('/', function() {
Flight::response()->header('Content-Type', 'text/plain');
// или
Flight::response()->setHeader('Content-Type', 'text/plain');
echo "Hello, World!";
});
Перенаправление
Вы можете перенаправить текущий запрос, используя метод redirect()
и передав новый URL:
Flight::route('/login', function() {
$username = Flight::request()->data->username;
$password = Flight::request()->data->password;
$passwordConfirm = Flight::request()->data->password_confirm;
if($password !== $passwordConfirm) {
Flight::redirect('/new/location');
return; // это необходимо, чтобы функциональность ниже не выполнялась
}
// добавьте нового пользователя...
Flight::db()->runQuery("INSERT INTO users ....");
Flight::redirect('/admin/dashboard');
});
Примечание: По умолчанию Flight отправляет HTTP 303 ("See Other") код статуса. Вы можете опционально установить пользовательский код:
Flight::redirect('/new/location', 301); // постоянный
Остановка выполнения маршрута
Вы можете остановить фреймворк и немедленно выйти в любой момент, вызвав метод halt
:
Flight::halt();
Вы также можете указать опциональный код статуса HTTP
и сообщение:
Flight::halt(200, 'Be right back...');
Вызов halt
отбросит любое содержимое ответа до этого момента и остановит все выполнение. Если вы хотите остановить фреймворк и вывести текущий ответ, используйте метод stop
:
Flight::stop($httpStatusCode = null);
Примечание:
Flight::stop()
имеет некоторые странные поведения, такие как вывод ответа, но продолжение выполнения вашего скрипта, что может быть не тем, что вы хотите. Вы можете использоватьexit
илиreturn
после вызоваFlight::stop()
, чтобы предотвратить дальнейшее выполнение, но в целом рекомендуется использоватьFlight::halt()
.
Это сохранит ключ и значение заголовка в объекте ответа. В конце жизненного цикла запроса он построит заголовки и отправит ответ.
Расширенное использование
Отправка заголовка немедленно
Могут быть случаи, когда вам нужно сделать что-то пользовательское с заголовком, и вам нужно отправить заголовок на той самой строке кода, с которой вы работаете. Если вы устанавливаете потоковый маршрут, это то, что вам понадобится. Это достижимо через response()->setRealHeader()
.
Flight::route('/', function() {
Flight::response()->setRealHeader('Content-Type: text/plain');
echo 'Streaming response...';
sleep(5);
echo 'Done!';
})->stream();
JSONP
Для JSONP-запросов вы можете опционально передать имя параметра запроса, которое вы используете для определения вашей функции обратного вызова:
Flight::jsonp(['id' => 123], 'q');
Таким образом, при выполнении GET-запроса с использованием ?q=my_func
вы должны получить вывод:
my_func({"id":123});
Если вы не передадите имя параметра запроса, оно по умолчанию будет jsonp
.
Примечание: Если вы все еще используете JSONP-запросы в 2025 году и позже, присоединяйтесь к чату и расскажите нам почему! Мы любим слышать хорошие истории сражений/ужасов!
Очистка данных ответа
Вы можете очистить тело ответа и заголовки, используя метод clear()
. Это очистит любые заголовки, назначенные ответу, очистит тело ответа и установит код статуса в 200
.
Flight::response()->clear();
Очистка только тела ответа
Если вы хотите очистить только тело ответа, вы можете использовать метод clearBody()
:
// Это все еще сохранит любые заголовки, установленные на объекте response().
// Это все еще сохранит любые заголовки, установленные на объекте response().
Flight::response()->clearBody();
Кэширование HTTP
Flight предоставляет встроенную поддержку кэширования на уровне HTTP. Если условие кэширования выполнено, Flight вернет HTTP-ответ 304 Not Modified
. В следующий раз, когда клиент запросит тот же ресурс, ему будет предложено использовать локально кэшированную версию.
Кэширование на уровне маршрута
Если вы хотите кэшировать весь свой ответ, вы можете использовать метод cache()
и передать время кэширования.
// Это закэширует ответ на 5 минут
Flight::route('/news', function () {
Flight::response()->cache(time() + 300);
echo 'This content will be cached.';
});
// В качестве альтернативы вы можете использовать строку, которую вы бы передали
// методу strtotime()
Flight::route('/news', function () {
Flight::response()->cache('+5 minutes');
echo 'This content will be cached.';
});
Last-Modified
Вы можете использовать метод lastModified
и передать UNIX-временную метку для установки даты и времени последнего изменения страницы. Клиент продолжит использовать свой кэш, пока значение последнего изменения не изменится.
Flight::route('/news', function () {
Flight::lastModified(1234567890);
echo 'This content will be cached.';
});
ETag
Кэширование ETag
похоже на Last-Modified
, за исключением того, что вы можете указать любой идентификатор, который вы хотите для ресурса:
Flight::route('/news', function () {
Flight::etag('my-unique-id');
echo 'This content will be cached.';
});
Имейте в виду, что вызов либо lastModified
, либо etag
установит и проверит значение кэша. Если значение кэша одинаково между запросами, Flight немедленно отправит ответ HTTP 304
и остановит обработку.
Скачивание файла
v3.12.0
Есть вспомогательный метод для потоковой передачи файла конечному пользователю. Вы можете использовать метод download
и передать путь.
Flight::route('/download', function () {
Flight::download('/path/to/file.txt');
// Начиная с v3.17.1 вы можете указать пользовательское имя файла для скачивания
Flight::download('/path/to/file.txt', 'custom_name.txt');
});
См. также
- Маршрутизация — Как сопоставлять маршруты с контроллерами и рендерить представления.
- Запросы — Понимание того, как обрабатывать входящие запросы.
- Middleware — Использование middleware с маршрутами для аутентификации, логирования и т.д.
- Почему фреймворк? — Понимание преимуществ использования фреймворка вроде Flight.
- Расширение — Как расширять Flight своей собственной функциональностью.
Устранение неисправностей
- Если у вас проблемы с перенаправлениями, которые не работают, убедитесь, что вы добавили
return;
в метод. stop()
иhalt()
— это не одно и то же.halt()
остановит выполнение немедленно, в то время какstop()
позволит выполнению продолжаться.
Журнал изменений
- v3.17.1 — Добавлен
$fileName
в методdownloadFile()
. - v3.12.0 — Добавлен вспомогательный метод downloadFile.
- v3.10.0 — Добавлен
jsonHalt
. - v1.0 — Первое выпущение.