[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fUeZl8biJV2ndkY9H6mMUW_PPTqIiU7ETWQbfKmDaiN4":3},{"code":4,"message":5,"data":6},200,"成功",{"id":7,"createdAt":8,"title":9,"content":10,"summary":11,"image":12,"uid":13,"user":14,"categoryId":21,"category":22,"subCategoryId":24,"subCategory":25,"comments":27,"status":17,"reason":28,"notice":28,"visitCount":29,"commentCount":30,"keywords":31},149,"2025-02-24T11:19:15.509Z","在前端中获取视频video的md5 - SparkMD5","在有些场景中，会遇到需要获取文件，比如图片、视频的md5，那么在前端中如何做呢，这里和大家分享一下。\n\n## 背景\n在我的项目开发过程中，需要获取视频的md5，用以做视频校验以及安全性相关的策略。\n\n## md5策略\n我选择使用spark-md5这个库来做md5，原因是这个库相对来说是性能比较良好的md5算法库，具体的介绍，大家可以通过npm package中去查看：[https://www.npmjs.com/package/spark-md5](https://www.npmjs.com/package/spark-md5)\n\n![spark-md5 介绍](https://image.xinwei.ltd/image1740394988120.png)\n\n\n## md5的具体用法\npackage主页已经介绍了一些具体用法，我这里简要介绍一下：\n```js\n// 常用字符串整体md5\nvar hexHash = SparkMD5.hash('Hi there');        // hex hash\nvar rawHash = SparkMD5.hash('Hi there', true);  // OR raw hash (binary string)\n\n// 动态字符串md5\nvar spark = new SparkMD5();\nspark.append('Hi');\nspark.append(' there');\nvar hexHash = spark.end();                      // hex hash\nvar rawHash = spark.end(true);                  // OR raw hash (binary string)\n```\n\n官方给出了一个file的md5示例：\n```js\ndocument.getElementById('file').addEventListener('change', function () {\n    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,\n        file = this.files[0],\n        chunkSize = 2097152,                             // Read in chunks of 2MB\n        chunks = Math.ceil(file.size / chunkSize),\n        currentChunk = 0,\n        spark = new SparkMD5.ArrayBuffer(),\n        fileReader = new FileReader();\n\n    fileReader.onload = function (e) {\n        console.log('read chunk nr', currentChunk + 1, 'of', chunks);\n        spark.append(e.target.result);                   // Append array buffer\n        currentChunk++;\n\n        if (currentChunk \u003C chunks) {\n            loadNext();\n        } else {\n            console.log('finished loading');\n            console.info('computed hash', spark.end());  // Compute hash\n        }\n    };\n\n    fileReader.onerror = function () {\n        console.warn('oops, something went wrong.');\n    };\n\n    function loadNext() {\n        var start = currentChunk * chunkSize,\n            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;\n\n        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));\n    }\n\n    loadNext();\n});\n```\n\n但其实我们往往是在vue或者react的框架下做文件选取（图片、视频选取），所以我的用法很简单，下面是我的使用代码，仅供参考：\n```js\nimport SparkMD5 from 'spark-md5'\n\nconst readMp4Md5 = (file, callback) => {\n    var fileReader = new FileReader();\n    var spark = new SparkMD5.ArrayBuffer();\n    fileReader.readAsArrayBuffer(file);\n    fileReader.onload = (e) => {\n        spark.append(e.target.result);\n        var md5 = spark.end();\n        callback(md5);\n    };\n}\n```\n\n## 文件上传部分\n我直接使用了elemnt-plus中的`el-upload`组件，这里我贴出部分代码，用于做记录：\n```vue\n\u003Cel-upload\n   v-loading=\"appMp4Loading\"\n   v-model:file-list=\"row.appMp4List\"\n   :data=\"{index: 3}\"\n   :http-request=\"requestUpload\"\n   accept=\".mp4\"\n   :on-success=\"handleRowUploadChange(row, 3)\"\n   :show-file-list=\"false\"\n>\n    \u003Cdiv v-if=\"row.data.mp4.trim().length > 0\">\n        \u003Cvideo\n           :src=\"row.data.mp4\"\n           controls\n           controlslist=\"nodownload noplaybackrate\"\n           disablePictureInPicture \n           preload=\"metadata\"\n           width=\"200\"\n           height=\"200\"\n       >\n       \u003C/video>\n       \u003Cdiv style=\"font-size: 16px; color: #409eff;\">替换\u003C/div>\n   \u003C/div>\n   \u003Cel-button v-else type=\"primary\" link>+上传mp4视频\u003C/el-button>\n\u003C/el-upload>\n\n...\nconst requestUpload = (option)=>{\n      const { index } = option.data;\n      let param = {\n        course_id: 0,\n        file_name: option.file.name,\n      }\n      showUploadLoading(true, index);\n      return uploadCourseInfoApi(param).then((rst) => {\n            request({\n                url: rst.data.url,\n                method: 'put',\n                timeout: 360000,\n                data: option.file,\n                headers: { 'Content-Type': option.file.type },\n            }).then(res => {\n                if(res?.status>=200&&res?.status\u003C=300) {\n                    //上传成功 调用onSuccess方法，否则没有完成图标\n                    option.onSuccess(rst)\n                    ElMessage.success('上传成功');\n                }\n                showUploadLoading(false, index);\n            }).catch(err=>{\n                ElMessage.error('上传文件失败');\n                deleteUploadFailFielist(index);\n                showUploadLoading(false, index);\n            })\n        })\n        .catch(err=>{\n            ElMessage.error('获取上传地址失败');\n            deleteUploadFailFielist(index);\n            showUploadLoading(false, index);\n            option.onError()\n        })\n}\n\nconst handleRowUploadChange = (row, index) => {\n    let fileList = [];\n    if (index == 0) {\n        fileList = row.pngList || [];\n    } else if (index == 1) {\n        fileList = row.appGifList || [];\n    } else if (index == 2) {\n        fileList = row.keepGifList || [];\n    } else if (index == 3) {\n        fileList = row.appMp4List || [];\n    }\n    if (fileList.length == 0) return;\n    const firstResponse = fileList[fileList.length - 1].response;\n    if (!firstResponse) return;\n    const { code, data, msg } = firstResponse;\n    if (code == 0 && data && data.cdn_url) {\n        if (index == 0) {\n            row.data.png = data.cdn_url;\n        } else if (index == 1) {\n            row.data.app_gif = data.cdn_url;\n        } else if (index == 2) {\n            row.data.tool_gif = data.cdn_url;\n        } else if (index == 3) {\n            row.data.mp4 = data.cdn_url;\n            if (fileList.length > 0 && fileList[fileList.length - 1].raw) {\n                readMp4Md5(fileList[fileList.length - 1].raw, (md5) => {\n                    row.data.mp4_md5 = md5;\n                });\n            }\n        }\n    }\n}\n...\n```\n\n实用很简单，希望对大家有帮助。\n\n也希望大家多多关注公众号“新卫网络科技”。","在有些场景中，会遇到需要获取文件，比如图片、视频的md5，那么在前端中如何做呢，这里和大家分享一下。","https://image.xinwei.ltd/image1740394988120.png",499668042977349,{"phone":15,"userId":13,"nickName":16,"vipType":17,"avatar":18,"sign":19,"createdAt":20},"13121171998","全栈老韩",1,"https://image.xinwei.ltd/images/IMG_5430.JPG","全栈工程师，擅长iOS App开发、前端（vue、react、nuxt、小程序&Taro）开发、Flutter、React Native、后端（midwayjs、golang、express、koa）开发、docker容器、seo优化等。","2024-01-01T16:14:30.305Z",2,{"id":21,"name":23},"IT技术",32,{"id":24,"name":26,"parentId":21},"前端",[],"",224,0,"md5,spark-md5,video md5,vue md5,npm md5,video upload,el-upload"]