파일 업로드와 다운로드
파일 업로드
간단한 파일 업로드
go
package main
import (
"log"
"os"
"github.com/cybergodev/httpc"
)
func main() {
fileContent, err := os.ReadFile("document.pdf")
if err != nil {
log.Fatal(err)
}
result, err := httpc.Post("https://api.example.com/upload",
httpc.WithFile("file", "document.pdf", fileContent),
)
if err != nil {
log.Fatal(err)
}
log.Printf("업로드 완료: %d", result.StatusCode()) // 출력 예시: 업로드 완료: 200 (실제 상태 코드는 서버에 따라 다름)
}Multipart 폼
파일과 함께 폼 필드를 업로드합니다:
go
form := &httpc.FormData{
Fields: map[string]string{
"title": "My Document",
"type": "pdf",
},
Files: map[string]*httpc.FileData{
"file": {
Filename: "report.pdf",
Content: fileContent,
},
},
}
result, err := httpc.Post("https://api.example.com/upload",
httpc.WithFormData(form),
)다중 파일 업로드
go
form := &httpc.FormData{
Fields: map[string]string{
"description": "일괄 업로드",
},
Files: map[string]*httpc.FileData{
"file1": {Filename: "doc1.pdf", Content: content1},
"file2": {Filename: "doc2.pdf", Content: content2},
"file3": {Filename: "image.png", Content: content3},
},
}
result, err := httpc.Post(url, httpc.WithFormData(form))바이너리 업로드
go
data, err := os.ReadFile("data.bin")
if err != nil {
log.Fatal(err)
}
result, err := httpc.Post(url,
httpc.WithBinary(data, "application/octet-stream"),
)
if err != nil {
log.Fatal(err)
}파일 다운로드
Download(ctx, url, cfg, options...)는 패키지 수준 함수, Client, DomainClient에 걸친 유일한 정규 다운로드 진입점입니다.
기본 다운로드
go
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/tmp/file.zip"
result, err := httpc.Download(context.Background(), "https://example.com/file.zip", cfg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("다운로드 완료: %s\n", httpc.FormatBytes(result.BytesWritten))
fmt.Printf("소요 시간: %v\n", result.Duration)진행률 콜백 포함
go
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/tmp/file.zip"
cfg.Overwrite = true
cfg.ProgressCallback = func(downloaded, total int64, speed float64) {
pct := float64(downloaded) / float64(total) * 100
fmt.Printf("\r다운로드 중: %.1f%% (%s)", pct, httpc.FormatSpeed(speed))
}
result, err := httpc.Download(context.Background(), "https://example.com/file.zip", cfg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n다운로드 완료: %s, 평균 속도 %s\n",
httpc.FormatBytes(result.BytesWritten),
httpc.FormatSpeed(result.AverageSpeed),
)이어받기
go
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/tmp/large-file.zip"
cfg.ResumeDownload = true
result, err := httpc.Download(context.Background(), url, cfg)
if err != nil {
log.Fatal(err)
}
if result.Resumed {
fmt.Printf("이어받기 완료: 중단 지점에서 복구\n")
}TIP
이어받기는 서버가 Range 요청 헤더를 지원해야 합니다. 서버가 지원하지 않는 경우 (206 대신 200 반환), 이미 다운로드된 부분 파일을 보호하기 위해 오류를 반환합니다.
컨텍스트 제어 포함
go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/tmp/file.zip"
result, err := httpc.Download(ctx, url, cfg)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Println("다운로드 타임아웃")
}
log.Fatal(err)
}보안 방어
파일 다운로드에 내장된 다층 보안 보호:
| 보호 계층 | 설명 |
|---|---|
| 경로 검증 | UNC 경로, 제어 문자, 경로 순회 차단 |
| 시스템 경로 보호 | /etc/, C:\Windows\ 등 시스템 디렉토리 쓰기 금지 |
| 심볼릭 링크 감지 | 심볼릭 링크 공격 방지 |
| 파일 크기 제한 | MaxResponseBodySize로 제한 |
도메인 클라이언트 다운로드
도메인 클라이언트의 다운로드는 응답 Cookie 를 세션에 자동으로 캡처합니다:
go
dc, err := httpc.NewDomain("https://api.example.com")
if err != nil {
log.Fatal(err)
}
defer dc.Close()
dc.SetHeader("Authorization", "Bearer "+token)
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/tmp/report.pdf"
// 다운로드 및 세션 자동 관리 (path 는 baseURL 에 상대적)
result, err := dc.Download(context.Background(), "/files/report.pdf", cfg)
if err != nil {
log.Fatal(err)
}다음 단계
- 파일 다운로드 API - 완전한 다운로드 API 참조
- 도메인 클라이언트와 세션 - 세션 관리
- 요청과 응답 - 기본 요청 가이드