在一般的产品开发过程中,大家多少会遇到上传视频功能的需求,往往我们采用的都是对视频大小进行限制等方法,来防止上传请求超时,导致上传失败。这时候可能将视频分片上传可以对你的项目有一个小小的体验优化。
本片文章前端是vue,后台基于PHP进行的分片上传,需要的小伙伴可以借鉴。
前端代码
template
<Upload
:show-upload-list="false"
:action="fileUrl2"
:before-upload="videoSaveToUrl" // 分片上传处理方法
:data="uploadData" // 上传时需要携带的参数 例如token之类的
:headers="header" // 请求头
:multiple="true"
>
// 上传按钮样式
</Upload>
移入方法
import { uploadByPieces } from "@/utils/upload"; //引入uploadByPieces方法
methods
// 分片上传
videoSaveToUrl(file) {
uploadByPieces({
file: file, // 获取到的视频文件
pieceSize: 3, // 分片大小 这里是3M一片
success: (data) => {
this.formValidate.video_link = data.file_path;
this.progress = 100; // 上传成功 进度条为100%
},
error: (e) => {
this.$Message.error(e.msg); //报错信息
},
uploading: (chunk, allChunk) => {
this.videoIng = true; // 上传时进度条展示 根据需要添加
let st = Math.floor((chunk / allChunk) * 100); 这里是用上传的第几片除以总片数进行百分比计算
this.progress = st;
},
});
return false;
},
utils/upload
import md5 from 'js-md5' //引入MD5加密
import { upload } from '@/api/upload.js' // 这里指前端调用接口的api方法
export const uploadByPieces = ({ file, pieceSize = 2, success, error, uploading }) => {
// 如果文件传入为空直接 return 返回
if (!file) return
let fileMD5 = ''// 总文件列表
const chunkSize = pieceSize * 1024 * 1024 // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize) // 总片数
console.log(chunkSize, chunkCount)
// 获取md5
const readFileMD5 = () => {
// 读取视频文件的md5
console.log("获取文件的MD5值")
let fileRederInstance = new FileReader()
console.log('file', file)
fileRederInstance.readAsBinaryString(file)
fileRederInstance.addEventListener('load', e => {
let fileBolb = e.target.result
fileMD5 = md5(fileBolb)
console.log('fileMD5', fileMD5)
console.log("文件未被上传,将分片上传")
readChunkMD5()
})
}
const getChunkInfo = (file, currentChunk, chunkSize) => {
let start = currentChunk * chunkSize
let end = Math.min(file.size, start + chunkSize)
let chunk = file.slice(start, end)
return { start, end, chunk }
}
// 针对每个文件进行chunk处理
const readChunkMD5 = async () => {
// 针对单个文件进行chunk上传
for (var i = 0; i < chunkCount; i++) {
const { chunk } = getChunkInfo(file, i, chunkSize)
console.log("总片数" + chunkCount)
console.log("分片后的数据---测试:" + i)
await uploadChunk({ chunk, currentChunk: i, chunkCount })
}
}
const uploadChunk = (chunkInfo) => {
// progressFun()
return new Promise((resolver, reject) => {
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
}
// 创建formData对象,下面是结合不同项目给后端传入的对象。
let fetchForm = new FormData()
fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1) // 第几片
fetchForm.append('chunkSize', chunkSize) // 分片大小的限制 例如限制 5M
fetchForm.append('currentChunkSize', chunkInfo.chunk.size) // 每一片的大小
fetchForm.append('file', chunkInfo.chunk) //每一片的文件
fetchForm.append('filename', file.name) // 文件名
fetchForm.append('totalChunks', chunkInfo.chunkCount) //总片数
fetchForm.append('md5', fileMD5)
upload(fetchForm, config).then(res => {
console.log("分片上传返回信息:", res)
if (res.data.code == 1) {
// // 结合不同项目 将成功的信息返回出去
// 下面如果在项目中没有用到可以不用打开注释
uploading(chunkInfo.currentChunk + 1, chunkInfo.chunkCount)
resolver(true)
} else if (res.data.code == 2) {
if (chunkInfo.currentChunk < chunkInfo.chunkCount - 1) {
console.log("分片上传成功")
} else {
// 当总数大于等于分片个数的时候
if ((chunkInfo.currentChunk + 1) == chunkInfo.chunkCount) {
console.log("文件开始------合并成功")
success(res.data)
}
}
}
}).catch((e) => {
error && error(e)
})
})
}
readFileMD5() // 开始执行代码
}
后端代码
控制器
/**
* 视频分片上传
* @return mixed
*/
public function videoUpload()
{
$data = $this->request->postMore([
['chunkNumber', 0],//第几分片
['currentChunkSize', 0],//分片大小
['chunkSize', 0],//总大小
['totalChunks', 0],//分片总数
['file', 'file'],//文件
['md5', ''],//MD5
['filename', ''],//文件名称
]);
$res = $this->service->videoUpload($data, $_FILES['file']);
return app('json')->success($res);
}
方法
/**
* 视频分片上传
* @param $data
* @param $file
* @return mixed
*/
public function videoUpload($data, $file)
{
$public_dir = app()->getRootPath() . 'public';
$dir = '/uploads/attach/' . date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d');
$all_dir = $public_dir . $dir;
if (!is_dir($all_dir)) mkdir($all_dir, 0777, true);
$filename = $all_dir . '/' . $data['filename'] . '__' . $data['chunkNumber'];
move_uploaded_file($file['tmp_name'], $filename);
$res['code'] = 0;
$res['msg'] = 'error';
$res['file_path'] = '';
if ($data['chunkNumber'] == $data['totalChunks']) {
$blob = '';
for ($i = 1; $i <= $data['totalChunks']; $i++) {
$blob .= file_get_contents($all_dir . '/' . $data['filename'] . '__' . $i);
}
file_put_contents($all_dir . '/' . $data['filename'], $blob);
for ($i = 1; $i <= $data['totalChunks']; $i++) {
@unlink($all_dir . '/' . $data['filename'] . '__' . $i);
}
if (file_exists($all_dir . '/' . $data['filename'])) {
$res['code'] = 2;
$res['msg'] = 'success';
$res['file_path'] = $dir . '/' . $data['filename'];
}
} else {
if (file_exists($all_dir . '/' . $data['filename'] . '__' . $data['chunkNumber'])) {
$res['code'] = 1;
$res['msg'] = 'waiting';
$res['file_path'] = '';
}
}
return $res;
}
以上就是视频分片上传的前后台的所有代码,其中有需求小伙伴可以自行加入视频上传验证,断点续传等操作。
参考文章:http://blog.ncmem.com/wordpress/2023/12/23/%e3%80%90%e5%89%8d%e5%90%8e%e5%8f%b0%e5%ae%8c%e6%95%b4%e7%89%88%e3%80%91%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%86%e7%89%87%e4%b8%8a%e4%bc%a0/
欢迎入群一起讨论
标签:console,chunkInfo,上传,file,分片,完整版,data From: https://www.cnblogs.com/songsu/p/17922707.html