HTTP 에서 평문 텍스트 뿐만 아니라 파일을 전달해야 할 수 있습니다.
서버 -> 클라이언트 파일 전달 (다운로드)
핸들러 함수에서 제공
func handleFunc(c *gin.Context) {
// file path in server
c.File("cat.PNG")
}
서버에 있는 파일을 전달하는 간단한 방법 입니다. 제공 할 서버내 파일 경로를 인자로 전달해 주면 됩니다.
var fs http.FileSystem = http.Dir("./")
func handleFunc(c *gin.Context) {
c.FileFromFS("cat.PNG", fs)
}
Go 1.16
에 추가된 io/fs
를 사용하는 방법 입니다.
func handleFunc(c *gin.Context) {
img, _ := os.Open("q.PNG")
imgData, _ := ioutil.ReadAll(img)
c.Data(http.StatusOK, "image/png", imgData)
}
[]byte
형태 파일을 전달 할 때 사용합니다. 주로 파일 후 처리 후 (이미지 자르기 등) 파일을 전송할 때 사용 합니다.
func handleFunc(c *gin.Context) {
img, _ := os.Open("q.PNG")
imgFileInfo, _ := img.Stat()
c.DataFromReader(
http.StatusOK, // http status code
imgFileInfo.Size(), // size
"image/png", // Content-Type
img, // io.Reader
nil, // extraHeaders - 캐시나 파일 정보를 작성
)
}
io.Reader
형태 파일 데이터를 전송 할 때 사용합니다.
라우터 에서 제공
r := gin.New()
r.Static("/assets", "/var/www")
// 첫번째 인자로 접속시
// 두번째 인자로 입력된 디렉토리를 루트로 파일 제공
r.StaticFS("/assets", http.Dir("/var/www"))
// 위 함수와 동일
// io/fs 패키지를 두번째 인자로 받음
r.StaticFile("/cat", "./cat.PNG")
// 파일 하나를 제공 할 때 사용
// 두번째 인자로 파일의 경로를 받음
헤더
HTTP 헤더 설정에 따라 브라우저에 브라우징 되거나, 파일이 다운로드 될 수 있습니다. 명시적으로 파일이 다운로드 되도록 하려면 다음 헤더를 설정 합니다.
Content-Type: <파일 타입>
파일의 타입을 명시합니다. 다음 링크를 참고하세요
Content-Length: <파일 바이트 사이즈>
파일 크기를 바이트 단위 10진수 숫자로 명시합니다.
Content-Disposition: attachment; filename="<파일 이름>"
파일이 다운로드 될 파일임을 명시 합니다. 파일이름이 한국어 일 경우 인코딩이 필요할 수 있습니다.
Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt
Content-Transfer-Encoding: binary
전송 인크딩을 바이너리로 설정 합니다.
Cache-Control: no-store, no-cache, must-revalidate, Post-Check=0, Pre-Check=0
파일 캐시를 비활성화 합니다.
클라이언트 -> 서버 파일 전달 (업로드)
단일 파일
func main() {
r := gin.New()
// 업로드 메모리 용량 설정 - 필요시 사용
r.MaxMultipartMemory = 8 << 20 // 8 MiB
r.GET("/", serveUploadPage)
r.POST("/upload", uploadHandler)
r.Run(":8080")
}
// 싱글 파일 업로드 폼 HTML
const uploadPage string = `<html>
<head>
<title>파일 업로드</title>
<meta charset="utf-8">
</head>
<body>
<h2>파일 업로드</h2>
<form action="/upload" method="POST" enctype="multipart/form-data">
upload file: <input type="file" name="file">
<input type="submit" value="Submit">
</form>
</body>
</html>`
// 업로드 폼 제공 핸들러
func serveUploadPage(c *gin.Context) {
c.Data(http.StatusOK, "text/html", []byte(uploadPage))
}
// 싱글 파일 업로드 핸들러
func uploadHandler(c *gin.Context) {
// Single file
file, _ := c.FormFile("file")
log.Println(file.Filename + " uploaded")
// 파일 저장
// 방법 1.
// 기본 제공 함수로 파일 저장
c.SaveUploadedFile(file, filepath.Join("./uploaded", file.Filename))
//
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
}
싱글 파일 업로드 핸들러 입니다. 기본 제공하는 SaveUploadedFile()
를 사용하거나, FormFile()
이 리턴 한 file
을 Open()
함수로 Reader
인터페이스로 받아 사용할 수 있습니다.
주의 사항으로 업로드 된 파일의 이름 file.Filename
은 신뢰해선 안됩니다.
참고: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
src, _ := file.Open()
defer src.Close()
out, _ := os.Create(filepath.Join("./uploaded", file.Filename))
defer out.Close()
io.Copy(out, src)
SaveUploadedFile()
함수 대신 위처럼 직접 업로드한 파일 Reader
에 직접 접근 할 수 있습니다.
다중 파일
func main() {
r := gin.New()
// 업로드 메모리 용량 설정 - 필요시 사용
r.MaxMultipartMemory = 8 << 20 // 8 MiB
r.GET("/", serveUploadPage)
r.POST("/upload", uploadHandler)
r.Run(":8080")
}
// 다중 파일 업로드 폼 HTML
const uploadPage string = `<html>
<head>
<title>파일 업로드</title>
<meta charset="utf-8">
</head>
<body>
<h2>파일 업로드</h2>
<form action="/upload" method="POST" enctype="multipart/form-data">
upload file: <input type="file" name="upload[]" multiple>
<input type="submit" value="Submit">
</form>
</body>
</html>`
// 업로드 폼 제공 핸들러
func serveUploadPage(c *gin.Context) {
c.Data(http.StatusOK, "text/html", []byte(uploadPage))
}
// 다중 파일 업로드 핸들러
func uploadHandler(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
// Uploaded files
files := form.File["upload[]"]
// for range 로 업로드한 파일 순회
for _, file := range files {
log.Println(file.Filename)
c.SaveUploadedFile(file, filepath.Join("./uploaded", file.Filename))
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
}