golang 实现文件下载
package main import ( "fmt" "html/template" "io" "io/fs" "mime" "net/http" "os" "path/filepath" "regexp" "strconv" ) func getFiles(dir string) ([]string, error) { var files []string err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if !d.IsDir() { files = append(files, path) } return nil }) return files, err } type FileInfo struct { Name string URL string } var fileListTemplate = template.Must(template.New("fileList").Parse(` <html> <head><title>Available Files</title></head> <body> <h1>Available Files</h1> <ul> {{range .}} <li><a href="{{.URL}}">{{.Name}}</a></li> {{end}} </ul> </body> </html> `)) func listFilesHandler(w http.ResponseWriter, r *http.Request) { files, err := getFiles("G:\\Databackup") // 假设文件存储在项目根目录下的"files"目录 if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } var fileInfos []FileInfo for _, filePath := range files { fileName := filepath.Base(filePath) fileInfos = append(fileInfos, FileInfo{Name: fileName, URL: "/" + fileName}) } fileListTemplate.Execute(w, fileInfos) } func downloadFileHandler(w http.ResponseWriter, r *http.Request) { // 获取请求中的文件名 fileName := r.URL.Path[1:] // 去掉前导斜杠 // 安全检查:确保文件名仅包含合法字符,避免路径穿越攻击 if !isValidFileName(fileName) { http.Error(w, "Invalid file name", http.StatusForbidden) return } // 构建完整文件路径 filePath := "G:\\Databackup" + fileName // 打开文件并设置响应头 file, err := os.Open(filePath) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } defer file.Close() fileInfo, err := file.Stat() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } contentType := mime.TypeByExtension(filepath.Ext(fileName)) if contentType == "" { contentType = "application/octet-stream" // 默认未知类型为二进制流 } w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName)) w.Header().Set("Content-Length", strconv.FormatInt(fileInfo.Size(), 10)) // 发送文件内容到客户端 io.Copy(w, file) } func isValidFileName(name string) bool { // 实现一个简单的检查函数,仅允许字母、数字、下划线和点(用于扩展名) // 这里仅为示例,实际应用中可能需要更严格的过滤规则 return regexp.MustCompile(`^[A-Za-z0-9._]+$`).MatchString(name) } func main() { http.HandleFunc("/", listFilesHandler) http.HandleFunc("/download", downloadFileHandler) port := ":8080" // 可以根据需要调整监听端口 fmt.Printf("Listening on port %s for file listing and downloads.\n", port) err := http.ListenAndServe(port, nil) if err != nil { panic(err) } }View Code
标签:files,文件,return,err,fileName,golang,Error,http,下载 From: https://www.cnblogs.com/jason-zhao/p/18156194