当前位置: 首页 > ds >正文

大文件上传,对接阿里oss采用前端分片技术。完成对应需求!

最近做了一个大文件分片上传的功能,记录下

1. 首先是安装阿里云 oss 扩展

composer require aliyuncs/oss-sdk-php

去阿里云 oss 获取配置文件

AccessKey ID = ***
AccessKey Secret = ***
Bucket名称 = ***
Endpoint = ***

2. 前端上传,对文件进行分片

<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""><div class="form-group"><label class="control-label col-xs-12 col-sm-2">{:__('选择本地文件')}:</label><div class="col-xs-12 col-sm-8"><input type="file" id="fileInput"><div><a href="#" onclick="startUpload()"><i class="fa fa-upload"></i>选择完点击上传(请等待上传完成)</a></div><div id="progress" style="margin-top:10px;"></div></div></div><div class="form-group layer-footer"><label class="control-label col-xs-12 col-sm-2"></label><div class="col-xs-12 col-sm-8"><button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button></div></div>
</form><script>let chunkSize = 5 * 1024 * 1024; // 分片大小5MBlet uploadId = '';let objectName = '';let parts = [];const CHUNK_SIZE = 5 * 1024 * 1024; // 分片阈值5MBasync function startUpload() {const file = document.getElementById('fileInput').files[0];if (!file) {layer.msg('请选择文件', {icon: 1});}// 根据文件大小选择上传方式if (file.size <= CHUNK_SIZE) {await directUpload(file);} else {await chunkedUpload(file);}}// 开始上传async function directUpload(file) {const formData = new FormData();formData.append('file', file);formData.append('file_name', file.name);// 显示进度条const progressBar = document.getElementById('progress');progressBar.innerHTML = '上传进度:0%';try {const res = await fetch('/api/directUpload', {method: 'POST',body: formData,});const data = await res.json();if (data.code === 1) {progressBar.innerHTML = '上传进度:100%';$("#c-name").val(data.name);$("#c-fullurl").val(data.fullurl);layer.msg('上传成功', {icon: 1});} else {throw new Error(data.msg);}} catch (error) {progressBar.innerHTML = '上传失败';console.error('直接上传失败:', error);}}async function chunkedUpload(file) {const totalChunks = Math.ceil(file.size / CHUNK_SIZE);let uploadedChunks = 0;// 初始化分片上传const initRes = await fetch('api/initUpload', {method: 'POST',body: JSON.stringify({filename: file.name}),headers: {'Content-Type': 'application/json'}});const initData = await initRes.json();if (initData.code !== 1) return alert('初始化失败');const {uploadId, objectName} = initData;const parts = [];// 上传所有分片for (let i = 0; i < totalChunks; i++) {const start = i * CHUNK_SIZE;const end = Math.min(start + CHUNK_SIZE, file.size);const chunk = file.slice(start, end);const formData = new FormData();formData.append('part', chunk);formData.append('uploadId', uploadId);formData.append('objectName', objectName);formData.append('partNumber', i + 1);const uploadRes = await fetch('api/uploadPart', {method: 'POST',body: formData});const partData = await uploadRes.json();if (partData.code === 1) {parts.push({PartNumber: partData.partNumber,ETag: partData.etag});uploadedChunks++;// 更新进度const progress = (uploadedChunks / totalChunks * 100).toFixed(2);document.getElementById('progress').innerHTML = `上传进度:${progress}%`;}}// 合并分片const completeRes = await fetch('api/completeUpload', {method: 'POST',body: JSON.stringify({uploadId,objectName,parts: JSON.stringify(parts)}),headers: {'Content-Type': 'application/json'}});const completeData = await completeRes.json();if (completeData.code === 1) {$("#c-name").val(completeData.name);$("#c-fullurl").val(completeData.fullurl);layer.msg('上传成功', {icon: 1});} else {layer.msg('上传失败' + completeData.msg, {icon: 2});}}
</script>

2. 后端控制器

<?phpnamespace app\****;use OSS\Core\OssException;
use OSS\OssClient;class Attachment
{// 初始化分片上传public function initUpload(){$object = 'uploads/' . date('Ymd') . '/' . $this->request->post('filename');try {$ossClient = new OssClient(config('alioss.accessKeyId'),config('alioss.accessKeySecret'),config('alioss.endpoint'));$uploadId = $ossClient->initiateMultipartUpload(config('alioss.bucket'), $object);return json(['code' => 1,'uploadId' => $uploadId,'objectName' => $object]);} catch (OssException $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}// 上传分片public function uploadPart(){$data = $this->request->post();try {$ossClient = new OssClient(config('alioss.accessKeyId'),config('alioss.accessKeySecret'),config('alioss.endpoint'));$options = [OssClient::OSS_FILE_UPLOAD => $_FILES['part']['tmp_name'],OssClient::OSS_PART_NUM => $data['partNumber'],OssClient::OSS_CHECK_MD5 => true];$etag = $ossClient->uploadPart(config('alioss.bucket'),$data['objectName'],$data['uploadId'],$options);return json(['code' => 1,'etag' => $etag,'partNumber' => $data['partNumber']]);} catch (OssException $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}// 完成上传public function completeUpload(){$data = $this->request->post();try {$ossClient = new OssClient(config('alioss.accessKeyId'),config('alioss.accessKeySecret'),config('alioss.endpoint'));$result = $ossClient->completeMultipartUpload(config('alioss.bucket'),$data['objectName'],$data['uploadId'],json_decode($data['parts'], true));return json(['code' => 1,'url' => $result['oss-request-url'],'name' => pathinfo($data['objectName'], PATHINFO_FILENAME),'fullurl' => strstr($result['oss-request-url'], '?', true),]);} catch (OssException $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}// 直接上传完整文件public function directUpload(){try {$ossClient = new OssClient(config('alioss.accessKeyId'),config('alioss.accessKeySecret'),config('alioss.endpoint'));$file = $_FILES['file'];$file_name = $this->request->request('file_name', '');$object = 'uploads/' . date('Ymd') . '/' . $file['name'];$result = $ossClient->uploadFile(config('alioss.bucket'),$object,$file['tmp_name']);return json(['code' => 1,'url' => $result['oss-request-url'],'name' => pathinfo($file_name, PATHINFO_FILENAME),'fullurl' => $result['oss-request-url'],]);} catch (OssException $e) {return json(['code' => 0, 'msg' => $e->getMessage()]);}}
}
http://www.xdnf.cn/news/8706.html

相关文章:

  • 【MySQL】第7节|Mysql锁机制与优化实践以及MVCC底层原理剖析
  • ubuntu 安装latex
  • 清除 Ubuntu 磁盘空间
  • 安卓开发用到的设计模式(2)结构型模式
  • 开发者工具箱-鸿蒙金额转换开发笔记
  • R语言学习--Day08--bootstrap原理及误区
  • Ollama01-安装教程
  • 【MySQL】07.表内容的操作
  • Android 16系统源码_自由窗口(一)触发自由窗口模式
  • Gateway全局过滤器:接口耗时统计与黑白名单配置
  • R语言科研编程-柱状图
  • STM32 定时器输出比较深度解析:从原理到电机控制应用 (详解)
  • 黑马点评双拦截器和Threadlocal实现原理
  • 行列式的线性性质(仅限于单一行的加法拆分)
  • 电机控制储备知识学习(五) 三项直流无刷电机(BLDC)学习(四)
  • 思科硬件笔试面试题型解析
  • 7:OpenCV—图像形态学处理
  • 深度学习实战:从图像分类到文本生成的完整案例解析
  • DAY 35 模型可视化与推理
  • 力扣面试150题--求根节点到叶节点数字之和
  • 如何屏蔽mac电脑更新提醒,禁止系统更新(最新有效方法)
  • 5060显卡驱动PyCUDA开发环境搭建
  • 25. 日志装饰器的开发
  • 使用 Go 语言实现完整且轻量级高性能的 MQTT Broker
  • Vue3 Composition API: 企业级应用最佳实践方案
  • SDL2常用函数:SDL_Texture 数据结构及使用介绍
  • 微信小程序数据接收
  • 数据结构---二叉树
  • 基于python的机器学习(九)—— 评估算法(二)
  • OpenLayers 开发环境搭建