Laravel Lumen如何不使用presignedurl上传100MB APK至DigitalOcean
Lumen 上传80-100MB APK到DigitalOcean落地方案
首先明确:pion/laravel-chunk-upload完全支持Lumen,只是Lumen默认关闭Laravel的包自动发现机制,手动注册下服务提供者就能正常用,不需要换其他包。
第一步:先改基础运行配置,避免上传被拦截
不管用不用分片,先把基础限制调通:
- 修改
php.ini参数:post_max_size = 120Mupload_max_filesize = 110Mmax_execution_time = 120memory_limit = 256M
- 如果前端用Nginx反向代理,在对应站点的server配置块里加
client_max_body_size 120M;,改完重载Nginx。 - 打开
bootstrap/app.php,注册包的服务提供者:$app->register(\Pion\Laravel\ChunkUpload\ChunkUploadServiceProvider::class); - Lumen没有
vendor:publish命令,直接把vendor目录下pion/laravel-chunk-upload对应的config/chunk-upload.php文件复制到项目自身的config目录,临时分片存储路径改到本地磁盘剩余空间足够的目录即可。
第二步:前后端分片逻辑实现
前端随便选支持分片的上传组件(Uppy、WebUploader都可以),固定把APK按5MB单块大小切割,上传时携带三个核心参数:当前分片序号、分片总数量、文件唯一标识(可以用文件md5当标识,顺便支持断点续传)。
后端路由定义:
// routes/web.php $router->post('/apk/upload/chunk', 'UploadController@receiveChunk'); $router->get('/apk/upload/check', 'UploadController@checkUploadedChunk');
控制器核心代码:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Pion\Laravel\ChunkUpload\Receiver\FileReceiver; use Pion\Laravel\ChunkUpload\Handler\HandlerFactory; use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException; use Illuminate\Support\Facades\Storage; class UploadController extends Controller { /** * 查询已上传的分片,供前端做断点续传 */ public function checkUploadedChunk(Request $request) { $fileId = $request->input('identifier'); $chunkDir = storage_path('app/chunks/'.$fileId); $uploaded = []; if (is_dir($chunkDir)) { $uploaded = array_values(array_filter(scandir($chunkDir), function($name) { return !in_array($name, ['.', '..']); })); $uploaded = array_map('intval', $uploaded); } return response()->json(['uploaded_chunks' => $uploaded]); } /** * 接收分片,全部分片传完后自动合并转存到DigitalOcean */ public function receiveChunk(Request $request) { try { $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request)); if (!$receiver->isUploaded()) { throw new UploadMissingFileException('未接收到上传文件'); } $saveResult = $receiver->receive(); // 还在传分片阶段,直接返回成功 if ($saveResult->isChunkedUpload()) { return response()->json([ 'finished' => false, 'chunk_index' => $saveResult->chunk()->getIndex() ]); } // 全部分片上传完成,文件已经在本地合并完成 $mergedFile = $saveResult->getFile(); $storePath = 'apk/'.uniqid().'.apk'; // 流写入DigitalOcean Spaces,不占额外内存 Storage::disk('do_spaces')->writeStream( $storePath, fopen($mergedFile->getPathname(), 'r') ); // 清理本地临时分片和合并后的临时文件 $saveResult->delete(); return response()->json([ 'finished' => true, 'file_path' => $storePath ]); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } } }
第三步:配置DigitalOcean Spaces存储
DigitalOcean Spaces是S3兼容存储,直接用Flysystem的S3驱动就能对接:
- 根据自己的Lumen版本安装对应依赖:
- Lumen 9/10:
composer require league/flysystem-aws-s3-v3 "^3.0" - Lumen 6/7/8:装对应2.x/1.x版本即可
- Lumen 9/10:
- 在
config/filesystems.php里新增do_spaces磁盘配置:'disks' => [ // 其他原有磁盘配置 'do_spaces' => [ 'driver' => 's3', 'key' => env('DO_SPACES_ACCESS_KEY'), 'secret' => env('DO_SPACES_SECRET_KEY'), 'region' => env('DO_SPACES_REGION', 'sgp1'), 'bucket' => env('DO_SPACES_BUCKET'), 'endpoint' => env('DO_SPACES_ENDPOINT'), 'visibility' => 'private', // 公开下载就设为public 'throw' => false, ], ], - 在.env文件里填上自己在DO后台创建的Spaces密钥、区域、桶名、访问地址即可。
补充说明
- 临时分片目录要加定时清理任务,比如每天删除24小时前未完成合并的分片文件,避免磁盘空间被无效文件占满。
- 如果不想引入第三方包,自己实现分片逻辑也很简单:每接收一个分片就按序号存到对应文件id的临时目录,收到最后一个分片时按序号顺序把所有分片拼接成完整APK,再转存到DO即可,核心代码不超过100行。
- 100MB的文件如果网络环境稳定,也可以不用分片,只要把第一步提到的PHP、Nginx上传大小限制调够,直接普通单文件上传也能正常跑,只是没有断点续传能力,弱网下上传失败率更高。
内容的提问来源于stack exchange,提问作者sagar dhakal
相关产品推荐
相关产品推荐

