我有一个Laravel 5.4应用程序,经过身份验证的用户需要能够从S3存储中下载私有文件。我已经设置了一个路由和控制器来允许私人文件下载。
代码如下所示:
路线:
Route::get('file/{filename}', 'FileController@download')->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 docs。
中找到我的问题:什么是首选方式,每种方法的优点/缺点是什么?
到目前为止我收集的内容:
流:
下载:
答案 0 :(得分:8)
当您向Laravel调用response()
帮助程序时,它会返回Illuminate\Routing\ResponseFactory
的实例。 ResponseFactory
有以下两种方法:download
和stream
- 这两种方法都有问题。如果你深入挖掘,你会看到download
返回\Symfony\Component\HttpFoundation\BinaryFileResponse
的实例,而stream
返回\Symfony\Component\HttpFoundation\StreamedResponse
- 这些都是Symfony组件。
在这里挖掘代码是没有必要的,但是了解一下发生了什么是很好的。现在我们知道返回的底层对象来自Symfony HTTP组件,我们可以参考Symfony文档并查看它们推荐使用的内容。通常,在文件大小未知时使用流,例如在动态生成文件时。在大多数其他情况下,BinaryFileResponse
方法生成的download
足以满足您的需求。
您可以查看有关HTTP Streaming及其用例here的更深入的解释。