일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- RTK
- 웹애플리케이션서버
- frontend
- component
- JPA
- java
- springboot
- css
- javascript
- satisfiles
- hook
- tanstackquery
- ReactHooks
- backend
- storybook
- JavaSpring
- React
- typescript
- 티스토리챌린지
- Chakra
- Gin
- react-hook-form
- golang
- Redux
- 오블완
- Spring
- go
- test
- designpatterns
- Today
- Total
bkdragon's log
[go] io 패키지 본문
최근 golang 을 공부 중이다. 개인적인 관심도 있었고 업무에 사용할 일이 생겼기 떄문이다.
io 란
golang의 io 패키지는 표준 패키지로서 http 요청과 응답 , 파일, 메모리 버퍼, 네트워크 소켓 등의 입출력을 처리한다.
io 패키지의 주요 인터페이스
- io.Reader
데이터를 읽어오는 인터페이스. 데이터를 연속적인 스트림으로 처리할 수 있다. http의 request body가 io.Reader 이다.
type Reader interface {
Read(p []byte) (n int, err error)
}
Read라는 메서드를 가지고 있다. Read는 byte 슬라이스에 데이터를 읽어오고 다 읽으먄 EOF(end of file) 에러를 던진다.
스트림 데이터를 이렇게 처리할 수 있다.
for {
n, err := resp.Body.Read(buffer)
log.Println(buffer)
if err != nil {
if err == io.EOF {
// 정상적인 스트림 종료
break
}
// 비정상적인 스트림 종료
return err
}
if n > 0 {
// 데이터가 정상일 때 처리
}
}
근데 보통 io 패키지에서 제공하는 io.ReadAll 을 사용해서 Body를 읽는다.
아래는 http 요청을 처리하는 handler 인데 바디에서 ReadAll로 데이터를 읽는 것을 보여준다. (추가적으로 언마샬링, 마샬링, Writer에 데이터를 쓰는것까지 나오는데 아래에서 계속 설명하겠다.)
func handler(w http.ResponseWriter, r *http.Request) {
// HTTP 요청 바디에서 데이터를 읽음
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close()
// JSON 데이터를 구조체로 변환
var requestData RequestData
err = json.Unmarshal(body, &requestData)
if err != nil {
http.Error(w, "Failed to parse JSON", http.StatusBadRequest)
return
}
// 읽어온 데이터 출력
fmt.Printf("Received: Name=%s, Age=%d\n", requestData.Name, requestData.Age)
// 응답 생성
response := fmt.Sprintf("Hello, %s! You are %d years old.", requestData.Name, requestData.Age)
w.Write([]byte(response)) // HTTP 응답에 데이터를 씀
}
- io.Writer
데이터를 쓰기 위한 인터페이스이다. http response 가 이 인터페이스이다.
type Writer interface {
Write(p []byte) (n int, err error)
}
Write 메서드는 http response 에 데이터를 쓴다. 위의 예제에서 쓰는 걸 보여주고 있다.
json 형태로도 보낼 수 있다.
func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
response := helloWorldResponse{Message: "HelloWorld"}
data, err := json.Marshal(response)
if err != nil {
panic("Ooops")
}
w.Write(data)
}
- io.Closer
열린 리소스를 닫기 위한 인터페이스.
type Closer interface {
Close() error
}
io 패키지의 주요 메서드
- ioReadAll
위의 예제에도 등장했는데 Reader의 모든 데이터를 읽어 byte 슬라이스에 저장한다.
스트림을 한번에 읽기 때문에 대용량(큰 파일)에 경우 비효율적일 수 있다.
func ReadAll(r Reader) ([]byte, error)
- io.Copy
Reader로 부터 데이터를 읽어서 Writer에 복사한다. 메모리에 데이터를 올리지 않아서 성능적으로 이점을 가진다.
func Copy(dst Writer, src Reader) (written int64, err error)
아래 코드는 리버스 프록시의 일부 코드인데 원본 서버로부터 받은 데이터를 응답 스트림(Writer)에 그대로 복사 하고 있다.
func (ps *ProxyService) handleHTTPResponse(c *gin.Context, resp *http.Response) error {
// 응답 스트림에 바로 쓰기
_, err := io.Copy(c.Writer, resp.Body)
return err
}
- io.TeeReader
Reader
로부터 데이터를 읽으면서, 읽은 데이터를 다른 Writer
에도 복사한다.. 즉, 데이터를 읽으면서 동시에 복사본을 다른 곳에 기록할 때 유용하다.
io
패키지 주요 활용처
- 파일 입출력 처리: 파일에서 데이터를 읽고 쓰는 작업을
io.Reader
와io.Writer
인터페이스를 통해 처리한다. - 네트워크 통신: 네트워크 연결에서 데이터를 입력(읽기)하고 출력(쓰기)하는 작업은
io.Reader
와io.Writer
인터페이스를 사용하여 처리한다. 예를 들어, TCP 연결에서 데이터를 읽고 쓰는 작업이 이에 해당한다. - 데이터 스트리밍: 데이터 소스에서 데이터를 스트리밍 방식으로 읽고, 다른 목적지로 전송하는 작업에서 효율적으로 사용할 수 있다.
hadler 예시 합치기
ReadAll 로 요청을 읽고 go 구조체를 바꾼뒤 응답 객체생성하여 json으로 바꾸고 응답에 쓰는 예시
func httpHandler(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Bad Request", 400)
return;
}
var requestDto helloWorldRequest
err = json.Unmarshal(body, &requestDto)
if err != nil {
http.Error(w, "Bad request", 400)
return
}
response := helloWorldResponse{Message: "hello" + requestDto.Name}
data, err :=json.Marshal(response)
if err != nil {
http.Error(w, "Server Error", 500)
}
w.Write(data)
}
http.Error 도 간단히 보자.
func Error(w ResponseWriter, error string, code int) {
h := w.Header()
h.Del("Content-Length")
h.Set("Content-Type", "text/plain; charset=utf-8")
h.Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(code)
fmt.Fprintln(w, error)
}
에러 메시지와 상태 코드를 응답에 쓰고 있는 걸 확인할 수 있다. 좀 더 편하게 에러를 작성할 수 있다.
'golang' 카테고리의 다른 글
[gin] Clean Architecture (1) | 2024.09.20 |
---|---|
[gorm] 다형성 관계 (0) | 2024.09.11 |
[go] http 통신 과정 (0) | 2024.09.10 |
[gin] JSON (1) | 2024.09.08 |
[gin] ShouldBindJSON (0) | 2024.09.08 |