Golang中如何获取API上传进度
Golang中如何获取API上传进度 我通过以下链接实现了上传功能:
http, upload, go, progress
但在上传过程中,我不知道如何通过另一个GET请求获取进度信息…
1 回复
更多关于Golang中如何获取API上传进度的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,要实现通过另一个GET请求获取上传进度,需要在上传过程中维护一个全局的进度状态,并在独立的HTTP端点中提供查询功能。以下是完整的实现方案:
1. 定义进度跟踪结构
package main
import (
"fmt"
"io"
"net/http"
"sync"
"time"
)
type UploadProgress struct {
TotalBytes int64
BytesRead int64
UploadID string
StartTime time.Time
mu sync.RWMutex
}
var (
uploads = make(map[string]*UploadProgress)
uploadsMutex sync.RWMutex
)
2. 实现自定义Reader跟踪进度
type ProgressReader struct {
reader io.Reader
progress *UploadProgress
}
func (pr *ProgressReader) Read(p []byte) (int, error) {
n, err := pr.reader.Read(p)
if n > 0 {
pr.progress.mu.Lock()
pr.progress.BytesRead += int64(n)
pr.progress.mu.Unlock()
}
return n, err
}
3. 实现文件上传处理器
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
uploadID := r.URL.Query().Get("upload_id")
if uploadID == "" {
uploadID = fmt.Sprintf("upload_%d", time.Now().UnixNano())
}
// 解析multipart表单
err := r.ParseMultipartForm(32 << 20) // 32MB
if err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "Failed to get file", http.StatusBadRequest)
return
}
defer file.Close()
// 创建进度跟踪
progress := &UploadProgress{
TotalBytes: header.Size,
BytesRead: 0,
UploadID: uploadID,
StartTime: time.Now(),
}
// 存储进度信息
uploadsMutex.Lock()
uploads[uploadID] = progress
uploadsMutex.Unlock()
// 清理函数
defer func() {
uploadsMutex.Lock()
delete(uploads, uploadID)
uploadsMutex.Unlock()
}()
// 使用进度跟踪Reader包装文件
progressReader := &ProgressReader{
reader: file,
progress: progress,
}
// 模拟文件处理(实际应用中可能是保存到磁盘或其他存储)
buffer := make([]byte, 1024)
for {
_, err := progressReader.Read(buffer)
if err == io.EOF {
break
}
if err != nil {
http.Error(w, "Upload failed", http.StatusInternalServerError)
return
}
// 模拟处理延迟
time.Sleep(10 * time.Millisecond)
}
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Upload completed: %s", uploadID)
}
4. 实现进度查询端点
func progressHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
uploadID := r.URL.Query().Get("upload_id")
if uploadID == "" {
http.Error(w, "Missing upload_id parameter", http.StatusBadRequest)
return
}
uploadsMutex.RLock()
progress, exists := uploads[uploadID]
uploadsMutex.RUnlock()
if !exists {
http.Error(w, "Upload not found", http.StatusNotFound)
return
}
progress.mu.RLock()
percentage := float64(0)
if progress.TotalBytes > 0 {
percentage = float64(progress.BytesRead) / float64(progress.TotalBytes) * 100
}
response := map[string]interface{}{
"upload_id": progress.UploadID,
"bytes_read": progress.BytesRead,
"total_bytes": progress.TotalBytes,
"percentage": fmt.Sprintf("%.2f", percentage),
"elapsed": time.Since(progress.StartTime).String(),
}
progress.mu.RUnlock()
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"upload_id":"%s","bytes_read":%d,"total_bytes":%d,"percentage":%s,"elapsed":"%s"}`,
response["upload_id"], response["bytes_read"], response["total_bytes"],
response["percentage"], response["elapsed"])
}
5. 主函数和路由设置
func main() {
http.HandleFunc("/upload", uploadHandler)
http.HandleFunc("/progress", progressHandler)
fmt.Println("Server starting on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("Server failed: %v\n", err)
}
}
使用示例
上传文件:
curl -X POST -F "file=@largefile.zip" "http://localhost:8080/upload?upload_id=test123"
查询进度:
curl "http://localhost:8080/progress?upload_id=test123"
响应示例:
{
"upload_id": "test123",
"bytes_read": 5242880,
"total_bytes": 10485760,
"percentage": "50.00",
"elapsed": "2.5s"
}
这个实现提供了线程安全的进度跟踪,支持并发上传,并通过独立的GET端点实时查询上传进度。在实际生产环境中,可以考虑使用Redis等外部存储来替代内存映射,以支持分布式部署。

