扩展:分块上传
===
### 初始化分块上传
~~~
// 初始化分块上传
func InitialMultipartUploadHandler(w http.ResponseWriter,r *http.Request,p httprouter.Params) {
// 1.解析用户请求信息
r.ParseForm()
username := r.PostForm.Get("username")
filehash := r.PostForm.Get("filehash")
filesize, err := strconv.ParseInt(r.PostForm.Get("filesize"), 10, 64)
if err != nil {
response.RespMsg(w,defs.ErrorBadRequest)
return
}
// 2.获得redis的连接
redisConn := redis.RedisConn.Get()
defer redisConn.Close()
// 3.生成分块上传的初始化信息
info := &MultipartUploadInfo{
FileHash:filehash,
FileSize:filesize,
UploadID:username + utils.TimeGetNowTimeStr(),
ChunkSize:5*1024*1024,// 5MD
ChunkCount:int(math.Ceil(float64(filesize)/(5*1024*1024))),// 转float64除法在向上取整
}
// 4.将初始化信息写入到redis缓存
redisConn.Do("set","name","age")
redisConn.Do("HSET","MP_" + info.UploadID,"chunkcount",info.ChunkCount)
redisConn.Do("HSET","MP_" + info.UploadID,"filehash",info.FileHash)
redisConn.Do("HSET","MP_" + info.UploadID,"filesize",info.FileSize)
redisConn.Do("HSET","MP_" + info.UploadID,"chunksize",info.ChunkSize)
// 5.将相应信息初始化数据返回到客户端
response.RespInputData(w,200,info)
}
~~~
### 上传文件分块
~~~
// 上传文件分块
func UploadPartHandler(w http.ResponseWriter,r *http.Request,p httprouter.Params) {
// 1.解析用户请求参数
r.ParseForm()
//username := r.Form.Get("username")
uploadId := r.Form.Get("uploadid")
chunkIndex := r.Form.Get("index")
// 2.获得redis连接池中的一个连接
redisConn := redis.RedisConn.Get()
defer redisConn.Close()
// 3.获得文件句柄,用于存储分块内容
path := "data/" + uploadId
err := utils.DirPing(path)
if err != nil {
response.RespMsg(w,defs.ErrorBadServer)
return
}
file := path + "/" + chunkIndex
openFile, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 00666)
if err != nil {
response.RespMsg(w,defs.ErrorBadServer)
return
}
defer openFile.Close()
data, _, err := r.FormFile("file")
defer data.Close()
if err != nil {
response.RespMsg(w,defs.ErrorBadRequest)
return
}
reader := bufio.NewReader(data)
writer := bufio.NewWriter(openFile)
buf := make([]byte, 1024*1024) // 1M buf
for {
_, err := reader.Read(buf)
if err == io.EOF {
break
}else if err != nil {
response.RespMsg(w,defs.ErrorBadRequest)
return
}else{
writer.Write(buf)
}
}
writer.Flush()
// 4.更新redis缓存状态
redisConn.Do("HSET","MP_"+uploadId,"chkidx_"+chunkIndex,1)
// 5.返回处理结果到客户端
response.RespInputMsg(w,200,"ok")
// 不足之处,客户端上传需要携带当前分块的hash,服务端校验确保文件的完整性
}
~~~
### 通知上传合并接口
~~~
// 通知上传合并接口
func CompleteUploadHandler(w http.ResponseWriter,r *http.Request,p httprouter.Params) {
// 1.解析请求参数
r.ParseForm()
upid := r.Form.Get("uploadid")
username := r.Form.Get("username")
filehash := r.Form.Get("filehash")
filesize := r.Form.Get("filesize")
filename := r.Form.Get("filename")
// 2.获得redis连接池的一个连接
redisConn := redis.RedisConn.Get()
defer redisConn.Close()
// 3.通过uploadid查询redis判断是否所有分块上传完成
values, e := redis2.Values(redisConn.Do("HGETALL", "MP_"+upid))
if e != nil {
response.RespMsg(w,defs.ErrorBadRequest)
return
}
totalCount := 0 // 上传完成数量
chunkCount := 0 // 总数量
for i:=0;i<len(values);i+=2{
k := string(values[i].([]byte))
v := string(values[i+1].([]byte))
if k == "chunkcount" {
totalCount,_=strconv.Atoi(v)
}else if strings.HasPrefix(k,"chkidx_") && v == "1" {
chunkCount += 1
}
}
// 不等就是上传没有完成
if totalCount != chunkCount {
response.RespMsg(w,defs.ErrorBadRequest)
return
}
// 4.合并分块
// 5.更新唯一文件表,更新用户文件表
// 6.相应处理结果
}
~~~
- 初认GOlang Web
- 关于环境配置
- 路由
- 路由进阶与目录架构
- 静态文件服务器
- 自定义Middleware
- 与MySQL起舞
- 主从模式概念
- 部署主从集群
- 分库分表
- 补充:事务
- 补充:常用SQL示例
- Template使用
- 一些小的,但是要知道的东西
- 调度任务
- 流控算法
- 鉴权
- JWT鉴权前置知识:加密解密
- session
- 文件上传与下载
- 带缓存读写拷贝io
- 参考
- 写好的文件上传
- 文件下载
- 拓展:秒传功能实现
- 扩展:分块上传和断点续传
- 扩展:分块上传
- 扩展:断点续传
- 扩展:分布式存储
- 部署ceph集群
- cephAuth
- go操作ceph集群
- 扩展:云存储
- go操作oss
- 补充:xorm框架
- 命令小结
- 补充:xorm框架高级部分
- 补充
- MongoDB
- 基础概念
- 简简单单NoSql
- 操作集合(Collection)
- 操作文档(Document)
- 带条件的文档 db.find
- 复杂条件抽文档 db.find
- redis
- redis操作
- go操作redis
- (新增)配置鉴权
- 密码学
- 文件校验算法
- 未来课程的安排
- RPC实践
- 爬虫
- 正则表达式
- 爬取手机号
- 爬取邮箱
- 爬取超链接
- 爬取身份证号
- 并发爬图片
- 扩展:CICD
- GO实现自动化部署系统
- 国际化支持
- 并发带来问题的解决
- GOWEB小知识
- Sync包讲解
- sync.Pool
- 千万级WebSocket消息推送
- 微服务入门:开篇
- 路由通讯
- RabbitMQ
- RabbitMQ工作原理和转发模式
- Dcoker 下 RabbitMQ and Ui
- Go操作RabbitMQ
- 初步微服务
- go-micro
- 补充:consul
- 快速入门
- 补充:consul超时
- 微服务架构
- 微服务架构全景图
- 服务注册和发现
- raft协议基本概念
- raft协议leader选举详解
- raft协议日志复制详解
- raft协议safefy详解
- rpc调用个服务监控
- etcd
- 命令行使用
- Golang操作etcd
- GO操作etcd OP方式 (分布式锁基础)
- etcd 分布式集群乐观锁
- (新增)鉴权
- 服务注册
- 服务发现原理
- 选项设计模式介绍
- 基于插件的注册组建
- 课前知识
- etcd注册开发1
- ffmpeg
- 2.0新的启航
- 高可用Mysql
- mysql逻辑架构
- 常见的MySQL高可用方案
- 索引
- MYSQL调优
- 什么影响了MYSQL的性能
- Mysql 服务器参数配置
- Go深入并发
- 基本同步原语
- 扩展同步原语
- 原子操作
- M P G 模型
- 简单的消息总线
- GoMicro入门
- GO任务池编写
- GO依赖注入
- 一些补充
- golang defer在什么时候执行
- 分布式理论篇(面试吹牛必备)
- CAP理论
- Raft协议
- 保证注册中心的可靠性
- 链路追踪
- 怎么实现强一致性