在 Web 开发中,文件上传 是常见需求,例如头像上传、文档存储、图片分享等功能。Go 语言的标准库
net/http
已经内置了对multipart/form-data
类型的支持,能让我们轻松构建一个文件上传服务。
本文将带你实现一个可运行的文件上传接口,并附带 HTML 表单和 curl
测试方法。
一、目标功能
- • 路径:
/upload
- • 方法:
POST
- • 表单字段:
- •
file
:上传文件 - •
desc
:文件描述(可选)
- •
- • 保存文件到本地
./uploads
目录 - • 返回 JSON 结果
二、核心知识点
- •
r.ParseMultipartForm(maxMemory)
:解析multipart/form-data
表单 - •
r.FormFile("file")
:获取上传的文件 - •
io.Copy(dst, src)
:保存文件到本地 - • 表单字段获取:
r.FormValue("desc")
- • 文件权限控制:
os.Create()
/os.MkdirAll()
三、完整代码
package mainimport ("encoding/json""fmt""io""net/http""os""path/filepath"
)type UploadResponse struct {Filename string `json:"filename"`Size int64 `json:"size"`Desc string `json:"desc"`Status string `json:"status"`
}func uploadHandler(w http.ResponseWriter, r *http.Request) {if r.Method != http.MethodPost {http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)return}// 解析上传表单(maxMemory 5MB,超过部分存临时文件)err := r.ParseMultipartForm(5 << 20)if err != nil {http.Error(w, "Error parsing form: "+err.Error(), http.StatusBadRequest)return}// 获取表单字段desc := r.FormValue("desc")// 获取文件file, handler, err := r.FormFile("file")if err != nil {http.Error(w, "Error retrieving file: "+err.Error(), http.StatusBadRequest)return}defer file.Close()// 确保保存目录存在os.MkdirAll("./uploads", os.ModePerm)// 保存文件filePath := filepath.Join("uploads", handler.Filename)dst, err := os.Create(filePath)if err != nil {http.Error(w, "Error saving file: "+err.Error(), http.StatusInternalServerError)return}defer dst.Close()size, err := io.Copy(dst, file)if err != nil {http.Error(w, "Error writing file: "+err.Error(), http.StatusInternalServerError)return}// 返回 JSON 响应w.Header().Set("Content-Type", "application/json")json.NewEncoder(w).Encode(UploadResponse{Filename: handler.Filename,Size: size,Desc: desc,Status: "success",})
}func main() {http.HandleFunc("/upload", uploadHandler)fmt.Println("文件上传服务已启动:http://localhost:8080/upload")http.ListenAndServe(":8080", nil)
}
四、测试方法
1. HTML 表单测试
保存为 upload.html
:
<!DOCTYPE html>
<html>
<body>
<h2>文件上传测试</h2>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">文件描述: <input type="text" name="desc"><br><br>选择文件: <input type="file" name="file"><br><br><input type="submit" value="上传">
</form>
</body>
</html>
打开浏览器选择文件并提交。
2. curl 命令测试
curl -X POST http://localhost:8080/upload \-F "desc=测试图片" \-F "file=@test.png"
五、运行效果
成功上传后返回:
{"filename": "test.png","size": 15324,"desc": "测试图片","status": "success"
}
文件会保存在 ./uploads/test.png
。
六、注意事项
- 1. 上传限制:
通过r.ParseMultipartForm(maxMemory)
控制内存占用,超过部分会写入临时文件。 - 2. 安全性:
- • 校验文件类型(避免执行恶意文件)
- • 生成唯一文件名(避免覆盖)
- • 设置合理的文件大小限制(可用
http.MaxBytesReader
)
- 3. 跨域请求:
如果前端与后端不在同一域名,需要设置Access-Control-Allow-Origin
等 CORS 头。
七、进阶扩展
- • 上传时自动生成文件唯一 ID(防止文件名冲突)
- • 返回文件访问 URL
- • 将文件上传到云存储(如 AWS S3、阿里云 OSS)
- • 支持多文件同时上传(
r.MultipartForm.File["file"]
)