擴展:分塊上傳
===
### 初始化分塊上傳
~~~
// 初始化分塊上傳
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協議
- 保證注冊中心的可靠性
- 鏈路追蹤
- 怎么實現強一致性