일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 방화벽체크
- Linux
- RUBY
- 드라이버
- ssh command
- docker registry
- DevOps
- VPN
- 루비
- opsworks
- sudo
- 패키지
- 리눅스
- docker-compose
- QT
- driver
- 도커
- Chef
- VIM
- docker container
- VMware
- ssh
- 우분투
- window size
- Openswan
- golang
- docker
- port
- ubuntu
- AWS
- Today
- Total
구리의 창고
Golang - http transport RoundTripper 사용 본문
개요
Golang의 http 패키지는 많은 편리한 기능을 들고 있다. 그 중 하나인 RoundTripper에 대해 소개해보려고한다.
요즘 개발을 하다보면 REST API 같은 http/https을 사용한 수 많은 라이브러리들을 접할 수 있다. 그리고 그 많은 API들은 전후처리가 연속적으로 필요한 경우가 생긴다.
전후처리에 대한 한 가지 예로, API의 Latency를 로깅하고 싶을 수 있다. 혹은 Basic Authentication이 필요한 API 들도 있다.
이를 좀 더 편하게 해주는게 RoundTripper다. 이름 그대로 코딩된 RoundTripper 순서대로 http 요청하기 전에 뭔가 작업을 할 수가 있다.
마치 미들웨어를 사용하는 느낌이드는 녀석이다.
긴 설명보다 코드가 이해하기 더 좋다. 아래 코드를 보자.
RoundTripper
RoundTripper는 Interface이다. 문서를 살펴보면 RoundTrip(*Request) (*Response, error)를 구현해줘야한다.
type RoundTripper interface {
RoundTrip(*Request) (*Response, error)
}
예제 코드1 (RoundTripper 사용 전)
위에 든 예 중, 간단하게 API Latency 로깅하는 것을 작성해보겠다.
일반적으로 아래처럼, 시간 체크를 앞 뒤로 두고 코드를 작성 할 수 있다.
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
client := http.DefaultClient
now := time.Now()
url := "https://ipinfo.io/8.8.8.8/json"
resp, err := client.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Printf("[DEBUG] url: %s, latency: %f seconds\n", url, time.Since(now).Seconds())
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
위 코드를 실행하면 다음과 같은 결과가 나온다.
[DEBUG] url: https://ipinfo.io/8.8.8.8/json, latency: 1.011706 seconds
{
"ip": "8.8.8.8",
"city": "Mountain View",
"region": "California",
"country": "US",
"loc": "37.3860,-122.0840",
"org": "AS15169 Google Inc.",
"postal": "94035",
"phone": "650"
}
예제 코드2 (RoundTripper 사용)
RoundTripper를 사용한 예제코드다.
http.DefaultClient의 Transport를 작성한 latencyTransport로 변경했다.
latencyTransport.RoundTrip에서는 맴버 변수로 있는 transport를 실행하고 Latency를 계산한다.
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
latencyTransport := newLatencyTransport(http.DefaultTransport)
client := http.DefaultClient
client.Transport = latencyTransport
resp, err := client.Get("https://ipinfo.io/json")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
type latencyTransport struct {
transport http.RoundTripper
}
func newLatencyTransport(t http.RoundTripper) http.RoundTripper {
return &latencyTransport{t}
}
func (t *latencyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
now := time.Now()
resp, err := t.transport.RoundTrip(req)
if err != nil {
return resp, err
}
fmt.Printf("[DEBUG] url: %s, latency: %f seconds\n", req.URL, time.Since(now).Seconds())
return resp, err
}
위 코드를 실행하면 역시 같은 결과가 나온다.
[DEBUG] url: https://ipinfo.io/8.8.8.8/json, latency: 1.011706 seconds
{
"ip": "8.8.8.8",
"city": "Mountain View",
"region": "California",
"country": "US",
"loc": "37.3860,-122.0840",
"org": "AS15169 Google Inc.",
"postal": "94035",
"phone": "650"
}
정리
위에 든 예는 블로그에 정리하기 위한 매우 간단한 경우다. 가장 유용하게 사용 할 수 있는 곳은 인증이 필요한 API라고 생각이된다. 아마 아래와 같은 플로우가 그려질 수 있을 것 같다.
1. API 요청
2. API 인증 실패 응답
3. API 인증 및 토큰 획득
4. API 토큰과 함께 다시 재시도
각 과정을 RoundTripper로 작성하게 된다면, 좀 더 깔끔하고 재활용 가능한 코드가 되지 않을까 싶다.
docker-registry-client 오픈소스에서 registry 인증 시 위와 비슷한 루틴으로 구현되어있다.
좀 더 자세한 코드를 보고 싶으면 https://github.com/heroku/docker-registry-client를 살펴보자.
'Golang' 카테고리의 다른 글
Golang - Google OAuth2 접속/인증 (Google Adsense) (0) | 2017.08.05 |
---|---|
Golang - 인자(Argument, Parameter) 파싱하기 FlagSet (0) | 2017.07.27 |
Comments