Загрузка файлов Laravel 5: stream() или загрузка()
У меня есть приложение Laravel 5.4, где аутентифицированные пользователи должны иметь возможность загружать личные файлы из хранилища S3. Я установил маршрут и контроллер, чтобы разрешить приватную загрузку файлов.
Код выглядит следующим образом:
Маршрут:
Route::get('file/{filename}', '[email protected]')->where(['filename' => '[A-Za-z0-9-._\/]+'])->name('file')->middleware('auth:employee');
Контроллер:
public function download($fileName)
{
if (!$fileName || !Storage::exists($fileName)) {
abort(404);
}
return response()->stream(function() use ($fileName) {
$stream = Storage::readStream($fileName);
fpassthru($stream);
if (is_resource($stream)) {
fclose($stream);
}
}, 200, [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Type' => Storage::mimeType($fileName),
'Content-Length' => Storage::size($fileName),
'Content-Disposition' => 'attachment; filename="' . basename($fileName) . '"',
'Pragma' => 'public',
]);
}
Все работает нормально, но когда я ближе посмотрел на Laravel docs, я обнаружил, что они просто говорят о response()->download()
.
Если я реализую такой ответ, мой код будет выглядеть так:
public function download($fileName)
{
if (!$fileName || !Storage::exists($fileName)) {
abort(404);
}
$file = Storage::get($fileName);
return response()->download($file, $fileName, [
'Content-Type' => Storage::mimeType($fileName),
]);
}
Обе функции можно найти в API-документах.
Мой вопрос: что было бы предпочтительным способом, и каковы преимущества/недостатки каждого?
Из того, что я собрал до сих пор:
Поток:
- Не требует загрузки всего файла в память
- Подходит для больших файлов
Скачать
Ответы
Ответ 1
Когда вы вызываете Laravel помощником response()
, он возвращает экземпляр Illuminate\Routing\ResponseFactory
. У ResponseFactory
есть эти два метода: download
и stream
- два рассматриваемых метода. Если вы покопаетесь немного глубже, вы увидите, что download
возвращает экземпляр \Symfony\Component\HttpFoundation\BinaryFileResponse
, а stream
возвращает \Symfony\Component\HttpFoundation\StreamedResponse
- это оба компонента Symfony.
Копаться в коде здесь не нужно, но приятно иметь представление о том, что происходит под капотом. Теперь, когда мы знаем, что возвращаемые базовые объекты взяты из HTTP-компонента Symfony, мы можем обратиться к документации Symfony и посмотреть, что они рекомендуют использовать. Обычно потоки используются, когда размер файла неизвестен, например, когда вы генерируете файл на лету. В большинстве других случаев BinaryFileResponse
, сгенерированный методом download
, будет достаточно для ваших нужд.
Вы можете взглянуть на более подробное объяснение потоковой передачи HTTP и ее вариантов использования здесь.