来自 Digital ocean spaces 的 Laravel 存储流文件的性能
Performance of Laravel storage streaming file from Digital ocean spaces
我通过搜索主题获得了以下代码
Route::get('/test', function () {
//disable execution time limit when downloading a big file.
set_time_limit(0);
$fs = Storage::disk('local');
$path = 'uploads/user-1/1653600850867.mp3';
$stream = $fs->readStream($path);
if (ob_get_level()) ob_end_clean();
return response()->stream(function () use ($stream) {
fpassthru($stream);
},
200,
[
'Accept-Ranges' => 'bytes',
'Content-Length' => 14098560,
'Content-Type' => 'application/octet-stream',
]);
});
但是,当我在 UI 上单击播放时,需要四秒钟才能开始播放。如果我将磁盘切换到本地,它几乎可以立即播放。
有没有办法提高性能,或者根据请求按范围读取流?
编辑
我目前的 DO 配置如下
'driver' => 's3',
'key' => env('DO_ACCESS_KEY_ID'),
'secret' => env('DO_SECRET_ACCESS_KEY'),
'region' => env('DO_DEFAULT_REGION'),
'bucket' => env('DO_BUCKET'),
'url' => env('DO_URL'),
'endpoint' => env('DO_ENDPOINT'),
'use_path_style_endpoint' => env('DO_USE_PATH_STYLE_ENDPOINT', false),
但我发现有两种在线集成,一种指定 CDN 端点,另一种不指定。我不确定哪个是相关的,尽管指定 CDN 的是 Laravel 8 而我在 Laravel 9.
我不得不更改我的代码:
- 我不得不使用 php SDK 客户端连接到 Aws,因为 Laravel API 不灵活,无法传递额外的参数(至少我还没有找到研究时的任何事情)
- 更改为 streamDownload,因为我在文档中看不到任何对流方法的描述,尽管它存在于代码中。
所以下面的代码可以实现我的目标,即根据请求中收到的范围按块下载。
return response()->streamDownload(function(){
$client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => config('filesystems.disks.do.region'),
'endpoint' => config('filesystems.disks.do.endpoint'),
'credentials' => [
'key' => config('filesystems.disks.do.key'),
'secret' => config('filesystems.disks.do.secret'),
],
]);
$path = 'uploads/user-1/1653600850867.mp3';
$range = request()->header('Range');
$result = $client->getObject([
'Bucket' => 'wyxos-streaming',
'Key' => $path,
'Range' => $range
]);
echo $result['Body'];
},
200,
[
'Accept-Ranges' => 'bytes',
'Content-Length' => 14098560,
'Content-Type' => 'application/octet-stream',
]);
注:
- 在实际场景中,如果未指定范围,则需要满足内容长度需要为实际文件大小
- 然而,当存在范围时,内容长度应该是被回显的段的大小
我通过搜索主题获得了以下代码
Route::get('/test', function () {
//disable execution time limit when downloading a big file.
set_time_limit(0);
$fs = Storage::disk('local');
$path = 'uploads/user-1/1653600850867.mp3';
$stream = $fs->readStream($path);
if (ob_get_level()) ob_end_clean();
return response()->stream(function () use ($stream) {
fpassthru($stream);
},
200,
[
'Accept-Ranges' => 'bytes',
'Content-Length' => 14098560,
'Content-Type' => 'application/octet-stream',
]);
});
但是,当我在 UI 上单击播放时,需要四秒钟才能开始播放。如果我将磁盘切换到本地,它几乎可以立即播放。
有没有办法提高性能,或者根据请求按范围读取流?
编辑
我目前的 DO 配置如下
'driver' => 's3',
'key' => env('DO_ACCESS_KEY_ID'),
'secret' => env('DO_SECRET_ACCESS_KEY'),
'region' => env('DO_DEFAULT_REGION'),
'bucket' => env('DO_BUCKET'),
'url' => env('DO_URL'),
'endpoint' => env('DO_ENDPOINT'),
'use_path_style_endpoint' => env('DO_USE_PATH_STYLE_ENDPOINT', false),
但我发现有两种在线集成,一种指定 CDN 端点,另一种不指定。我不确定哪个是相关的,尽管指定 CDN 的是 Laravel 8 而我在 Laravel 9.
我不得不更改我的代码:
- 我不得不使用 php SDK 客户端连接到 Aws,因为 Laravel API 不灵活,无法传递额外的参数(至少我还没有找到研究时的任何事情)
- 更改为 streamDownload,因为我在文档中看不到任何对流方法的描述,尽管它存在于代码中。
所以下面的代码可以实现我的目标,即根据请求中收到的范围按块下载。
return response()->streamDownload(function(){
$client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => config('filesystems.disks.do.region'),
'endpoint' => config('filesystems.disks.do.endpoint'),
'credentials' => [
'key' => config('filesystems.disks.do.key'),
'secret' => config('filesystems.disks.do.secret'),
],
]);
$path = 'uploads/user-1/1653600850867.mp3';
$range = request()->header('Range');
$result = $client->getObject([
'Bucket' => 'wyxos-streaming',
'Key' => $path,
'Range' => $range
]);
echo $result['Body'];
},
200,
[
'Accept-Ranges' => 'bytes',
'Content-Length' => 14098560,
'Content-Type' => 'application/octet-stream',
]);
注:
- 在实际场景中,如果未指定范围,则需要满足内容长度需要为实际文件大小
- 然而,当存在范围时,内容长度应该是被回显的段的大小