You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Lumen如何不使用presignedurl上传100MB APK至DigitalOcean

Lumen 上传80-100MB APK到DigitalOcean落地方案

首先明确:pion/laravel-chunk-upload完全支持Lumen,只是Lumen默认关闭Laravel的包自动发现机制,手动注册下服务提供者就能正常用,不需要换其他包。

第一步:先改基础运行配置,避免上传被拦截

不管用不用分片,先把基础限制调通:

  • 修改php.ini参数:
    • post_max_size = 120M
    • upload_max_filesize = 110M
    • max_execution_time = 120
    • memory_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版本即可
  • 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:18:22