假设要把项目做成微服务架构,然后单独做个静态资源服务器。
假如项目要做成微服务架构,像我最近做的一个国际项目,里头的日志,静态资源等需要抽离成独立的服务。。。巴拉巴拉省略一万字。
静态资源
假如把静态资源单独做成一个微服务, 可以选择搭建一个HDFS 。。。具体步骤(省略很多字)
文件服务hdfs
HDFS(Hadoop Distributed File System),作为Google File System(GFS)的实现,是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了很多便利。
适用、不适用的场景
1 | 高容错性、可构建在廉价机器上 |
HDFS局限
1 | 不支持低延迟访问 |
为什么要将文件分片
1、为了充分利用网络带宽,加快上传速度
2、避免断网,页面关闭等引起的文件上传失败导致文件丢失,需要重新上传
分片上传原理
将一个文件切割为一系列特定大小的小数据片,然后将这些小数据片分别上传到服务端,全部上传完后再由服务端将这些小数据片合并成为一个完整的资源。在上传的过程中即使遭受一些不确定因素影响导致上传中断,在恢复之后将继续该文件上次上传的进度继续上传,也就是断点续传。
举个栗子:
直接上传1
2
3传一个100M的文件,开始上传...0%..2%...99%...(断网) => 上传失败
然后再传一次,开始上传...0%..2%...99%...(某些原因造成页面关闭) => 上传失败
重新上传一次,开始上传...0%...
分片1
2100M的文件,每个数据片大小5M,分20片上传
开始上传...第一片...第二片...(断网)...第三片...(页面关闭)...第四片...(传完20片重组成文件)上传成功
后端:实现分片上传的前提是需要服务器记录某文件的上传进度,根据该文件的唯一标识判读是否是同一个文件,可以利用文件内容根据(修改时间+文件名称+最后修改时间)求MD5码,如果上传的文件过大,求MD5码也是个稍微漫长的过程,所以对于太大的文件,只能针对其中某一段数据进行MD5,加上其他的鉴权得到唯一的key。
前端:将文件按照按照一定大小进行分片,一般每片大小在5M左右,可以同时发起多个请求,但一次同时请求的连接数不宜过多,否则服务器负载过重。可以利用H5强大的File Api,通过File对象的slice方法切出文件的一部分,切出的数据片是Blob。
实现流程
1、选择文件
2、根据(修改时间+文件名称+最后修改时间)计算MD5,以此来实现断点续传及秒传的功能,所以要等MD5计算完毕之后,再开始文件上传的操作。
可以在这里做文件效验进度
3、通过文件的MD5查询文件是否已经存在
4、检查并上传MD5
可以在这里做文件上传进度
5、上传完所有分片之后通知服务器进行合并
具体实现
实现分片上传的方式有很多种:
百度的分片上传组件:WebUploader
vue-simple-uploader: vue-simple-uploader是基于 simple-uploader.js 封装的vue上传插件。使用之前瞄一眼vue-simple-uploader官方文档, simple-uploader.js官方文档…以及其他的花里胡哨
使用vue-simple-uploader
vue-simple-uploader的使用方法很简单,基本上就是配置参数1
npm i vue-simple-uploader
main.js或者其他导入的地方1
2
3import vueSimpleUploader from 'vue-simple-uploader';
Vue.use(vueSimpleUploader);
`
专门写个.vue文件来装它,叫upload-vue-simple-uploader.vue
template部分1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<template>
<uploader
:options="options"
:file-status-text="statusText"
@file-complete="fileComplete"
@complete="complete"
class="uploader-example"
>
<uploader-unsupport></uploader-unsupport>
<uploader-drop>
<p>请将文件拖拽到这里,或者</p>
<uploader-btn>请选择文件</uploader-btn>
<uploader-btn :attrs="attrs">请选择图片</uploader-btn>
<uploader-btn :directory="true">请选择目录</uploader-btn>
</uploader-drop>
<uploader-list></uploader-list>
</uploader>
</template>
js部分,options,attrs,statusText等都是它的配置项,可以翻看它的文档进行配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42export default {
data () {
return {
options: {
target: 'http://127.0.0.1:3000/upload', //上传地址
chunkSize: 5 * 1024 * 1024, //分片大小
testChunks: false, // 是否开启服务器分片校验(秒传)
maxChunkRetries: 3, //最大自动失败重试上传次数
checkChunkUploadedByResponse: function (chunk, message) {// 服务器分片校验,断点续传基础
let objMessage = JSON.parse(message);
if (objMessage.skipUpload) {
return true;
}
return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
},
headers: {
Authorization: "Bearer " + "your accessToken"
},
},
attrs: {
//接受的文件类型,形如['.png', '.jpg', '.jpeg', '.gif', '.bmp'...]
accept: 'image/*'
},
statusText: { //对应的状态说明
success: '上传成功',
error: '上传出错了',
uploading: '正在上传',
paused: '暂停中',
waiting: '等待中'
}
}
},
methods: {
complete () {
console.log('上传完成 complete', arguments)
},
fileComplete () {
console.log('文件上传完成 complete', arguments)
}
}
}
`
style1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16.uploader-example {
width: 880px;
padding: 15px;
margin: 40px auto 0;
font-size: 12px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {
margin-right: 4px;
}
.uploader-example .uploader-list {
max-height: 440px;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
}
使用的时候直接import然后在components里头注册然后直接在页面上用,当然这只是方便快捷简单粗暴的demo1
import UploadVueSimpleUploader from '@/components/upload-vue-simple-uploader'
上传一个我比较喜欢的千与千寻《神隐》的10M大小的mp3文件,发现它上传成功了,然后发了两次请求,因为设置的分片大小是5M所以会发两次请求
然后此时后端接收到的数据是这个样子的,然后后端再把它重组就成了文件
原生的方式
原生的方式比上面那个方式稍微复杂一些,但是比较可控,首先是有DOM,当然都是比较随意的布局,好看可以用ElementUI或者自己写写样式。1
npm install spark-md5
1 | <template> |
1 | let SparkMD5 = require('spark-md5') |
style lang=”stylus”1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.process-wrap {
width: 300px;
p {
width: 100%;
}
.progress {
background: #c5c8ce;
height: 20px;
position: relative;
span {
display: block;
background: #19be6b;
height: 100%;
width: 0;
}
}
}