I have a Laravel 5.4 app where authenticated users need to be able to download private files from S3 storage. I've setup a route and controller to allow private file downloads.

代码如下所示:

路由:

路由::get('file/{filename}', 'FileController@download')->where(['filename' => '[A-Za-z0-9-._\/]+'])->name('file')->middleware('auth:employee');

Controller:

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),
    ]);
}

Both functions can be found in the API docs.

My question: what would be the preferred way to go and what are the advantages/disadvantages of each?

From what I've gathered so far:

Stream:

  • Does not require the whole file to be loaded into memory
  • 适用于大文件

Download:

  • 需要更少的代码

推荐答案

调用Laravel response()助手时,它会返回Illuminate\Routing\ResponseFactory的一个实例.ResponseFactory有这两种方法:downloadstream——这两种方法都有问题.如果你再深入一点,你会发现download返回一个\Symfony\Component\HttpFoundation\BinaryFileResponse的实例,而stream返回一个\Symfony\Component\HttpFoundation\StreamedResponse——这两个都是Symfony组件.

Digging through the code here isn't necessary, but it is nice to have an understanding of what's going on under the hood. Now that we know the underlying objects returned are from the Symfony HTTP Component, we can consult the Symfony docs and see what they recommend using. Typically, streams are used when the size of the file is unknown, such as when you are generating the file on the fly. In most other cases, the BinaryFileResponse generated by the download method will be sufficient for your needs.

您可以更深入地了解HTTP流及其用例.

Laravel相关问答推荐

LaravelEloquent 的模型如何将值从控制器内部的函数传递到Render()

Vue 组件中的图像不适用于 Vite + Laravel

V-icon 在 Vuetify 3 中不显示图标

调用字符串上的成员函数

RuntimeException 未安装 Zip PHP 扩展

如何判断用户Electron邮件是否已存在

从 laravel/blade 中的数组创建逗号分隔列表?

Laravel 4,如何测试复选框是否被选中?

Homestead 2.0 多个站点,都链接到同一个 url

Laravel 4:读取由 javascript 设置的 cookie

Laravel Electron邮件验证模板位置

Homestead:文件夹映射到错误的文档根目录

如何在中间件 Laravel 中获取请求的控制器和操作的名称

SQLSTATE [01000]:警告:1265 列的数据被截断(truncated)

使用 laravel eloquent 关系检索除 NULL 之外的所有记录

为什么在 Laravel 的 DB::select 中使用 DB::raw?

Laravel Mail 发送Electron邮件但返回 false

Laravel 更新后用户模型错误(用户类包含 3 个抽象方法)

Laravel or where

Laravel 5 Auth注销不起作用