package main
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"regexp"
)
const (
uploadDir = "./uploads" // 文件存储目录
maxUploadSize = 10 << 20 // 10MB 最大文件大小
fileNameRegex = `^[a-zA-Z0-9_\-\.]+$` // 文件名正则规则
)
var validFileName = regexp.MustCompile(fileNameRegex)
func main() {
// 创建上传目录
if err := os.MkdirAll(uploadDir, 0755); err != nil {
panic(err)
}
http.HandleFunc("/upload", uploadHandler)
http.Handle("/files/", http.StripPrefix("/files/",
http.FileServer(http.Dir(uploadDir))))
fmt.Println("Server started at :9090")
http.ListenAndServe(":9090", nil)
}
// 上传处理函数
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 解析上传文件
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "Invalid file", http.StatusBadRequest)
return
}
defer file.Close()
// 校验文件名格式
if !validFileName.MatchString(header.Filename) {
http.Error(w, "Invalid file name format", http.StatusBadRequest)
return
}
// 创建目标文件
targetPath := filepath.Join(uploadDir, header.Filename)
dst, err := os.Create(targetPath)
if err != nil {
http.Error(w, "Failed to create file", http.StatusInternalServerError)
return
}
defer dst.Close()
// 复制文件内容
if _, err := io.Copy(dst, file); err != nil {
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, "File %s uploaded successfully", header.Filename)
}