在开发的过程中,难免会碰到上传/下载文件的场景。如果这个功能服务端没开发好,就没法进行测试。
所以每次都要自己先实现一遍,本文使用 go
写了一个简单的文件上传和下载服务。
以后再碰到这种场景的时候就可以快速进行开发。
因为下载比较简单, go
语言默认就有,所以先来说一下下载。
熟悉 go
的都知道, go
对文件服务器有默认的支持,所以我们直接调用相关的 API
就能完成对应的操作。
http.Handle("/", http.FileServer(http.Dir("/tmp/Downloads")))
http.ListenAndServe(":8080", nil)
在这里需要用 http
包中的 FileServer
函数,它需要一个文件夹,我这里使用的是一个临时目录 /tmp/Downloads
。
接着需要把这个 Handler
绑定到一个路由中,这里绑定的就是 /
。
最后需要启动这个服务,我把这个服务绑定到 8080
端口,然后使用 go run main.go
就可以运行服务器了。
你可以通过 http://localhost:8080/
来查看 /tmp/Downloads
下所有的文件。
与下载不同的是, go
没有提供默认的实现(也许有,我不知道),所以我们需要自己实现。
实现文件上传也比较简单
func uploadHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Receive Upload: ", time.Now())
file, header, err := r.FormFile("file")
if err != nil {
fmt.Println("Failed to get file data ", err.Error())
_, _ = io.WriteString(w, err.Error())
return
}
defer file.Close()
newFile, err := os.Create(header.Filename)
if err != nil {
fmt.Println("Failed to create file ", err.Error())
return
}
defer newFile.Close()
_, err = io.Copy(newFile, file)
if err != nil {
fmt.Println("Copy ", header.Filename, " to ", newFile.Name(), "failed ", err.Error())
return
}
fmt.Println("Upload File Success ", newFile.Name(), ",", time.Now())
}
func main() {
http.HandleFunc("/upload", uploadHandler)
http.ListenAndServe(":8080", nil)
}
我们把上传的逻辑放到 uploadHandler
这个函数中,并绑定到 /upload
这个路由上。
在 uploadHandler
中会从表单中读取 file
的文件,然后用它在本地创建一个同名的文件,接着把内容拷贝到新创建的本地文件中。这样就完成了。
现在我们就可以使用 curl
来测试一下上传文件
curl -X POST http://localhost:8080/upload \
-F "file=@/tmp/upload.go" \
-H "Content-Type: multipart/form-data"
不出所料,执行完成之后,在当前文件夹下多出了 upload.go
这个文件。
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Receive Upload: ", time.Now())
file, header, err := r.FormFile("file")
if err != nil {
fmt.Println("Failed to get file data ", err.Error())
_, _ = io.WriteString(w, err.Error())
return
}
defer file.Close()
newFile, err := os.Create(header.Filename)
if err != nil {
fmt.Println("Failed to create file ", err.Error())
return
}
defer newFile.Close()
_, err = io.Copy(newFile, file)
if err != nil {
fmt.Println("copy ", header.Filename, " to ", newFile.Name(), "failed ", err.Error())
return
}
fmt.Println("Upload File Success ", newFile.Name(), ",", time.Now())
}
func main() {
fmt.Println("Start Go Download Upload Server...")
http.HandleFunc("/upload", uploadHandler)
http.Handle("/", http.FileServer(http.Dir("/tmp/Downloads")))
http.ListenAndServe(":8080", nil)
}
往期推荐