728x90

IPv6 주소가 사용되는 곳이 많아지면서 curl 등으로 시험할 일도 종종 발생합니다.
curl은 오래전부터 IPv6에 대한 지원을 하고 있기 때문에 
왠만한 curl 버전을 사용중이라면 특별히 문제 없이 IPv6로 요청을 보낼 수 있습니다. 


브라켓을 이용하자

IPv4를 사용할때는 주소를 그대로 사용하는 것이 일반적입니다. 
다만 IPv6는 주소의 각 컴포넌트를 콜론(:)으로 구분하기 때문에 
명시적으로 IPv6 주소의 일부라는 것을 알려줄 필요가 있습니다. 

% curl 'https://[2404:6800:4004:80f::2004]' -v -k
*   Trying 2404:6800:4004:80f::2004:443...
* Connected to 2404:6800:4004:80f::2004 (2404:6800:4004:80f::2004) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/cert.pem
*  CApath: none

가령 위의 예시는 www.google.com  에 대한 IPv6 주소로 curl 요청을 보내는 예시입니다.
브라켓으로 IPv6 주소를 감싸고 있으며, 다시 전체 URL을 따옴표로 묶고 있는 것을 볼 수 있습니다.
따옴표를 쓰지 않으면 파싱에 문제가 생기니, IPv6 주소로 요청을 보낼때는 전체를 감싼다고 인식하시면 되겠습니다. 

 

resolve 에서 IPv6 활용하기

IPv6 주소를 직접 curl 대상 주소로 사용할 때는 위와 같습니다. 
간혹 IP Spoofing 을 해야 하는 경우 --resolve를 쓰고 계실텐데요, 
이때도 다음과 같은 형태로 IPv6 주소를 활용할 수 있습니다. 

% curl https://www.google.com --resolve www.google.com:443:'[2404:6800:4004:80f::2004]' -I
HTTP/2 200
content-type: text/html; charset=ISO-8859-1
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
date: Thu, 03 Feb 2022 08:37:37 GMT
server: gws
x-xss-protection: 0
x-frame-options: SAMEORIGIN
expires: Thu, 03 Feb 2022 08:37:37 GMT
...

--resolve를 사용할 때도 IPv6 주소를 브라켓으로 감싸고 따옴표를 넣어 주시면 되겠습니다. 
역시나 콜론이 많이 사용되고 있기 때문에 필요한 작업이라고 인식하면 되겠습니다. 

 

728x90
728x90

JSON을 다루는 것은 개발자에게는 숙명입니다. 그래도 SOAP 보다 편리하고 쉽다는게 어디냐며 위로해 보지만 할 때마다 새롭고 매번 처음 보는 것 같이 헤메는 것이 또한 JSON 다루기의 특징이기도 합니다.

터미널을 위시한 커맨드라인에서 jq를 이용하면 이런 번잡스러운 일을 간단하게 줄일 수 있습니다. 이미 많은 분들이 쓰고 있고 저 역시 쓰고 있지만 JSON을 다루는 만큼 매번 새롭기에... 하나씩 활용 방법을 찾아서 정리해보고자 합니다.


JSON은 단순히 어떤 요청에 대한 결과를 하나의 데이터 셋으로 내려주기도 하지만, 데이터 셋안에 여러개의 반복되는 데이터가 포함되어 있는 경우도 많습니다. 반복되는 JSON에서 원하는 속성의 값만을 뽑아내는 방법을 살펴보겠습니다. 

오늘의 데이터는 주택금융공사의
전세자금대출 고객 금리정보입니다.

 

시작부터 엄청 구미가 당기는 데이터이지 않습니까? 국가 공공데이터포털의 오픈API중에서 가장 먼저 눈에 띈 녀석으로 가져와 봤습니다. 여전히 SOAP만 제공하는 API도 많지만 많이 사용되는 데이터 셋은 JSON을 제공하는 경우가 많아 서비스를 개발하거나 연습할 때 무척 유용합니다. 

 

jq의 시작, jq '.' 사용하기

API의 자세한 스펙도 살펴보면 좋겠지만 우리의 목적은 흥미로운 JSON을 jq로 다뤄보는 연습을 하는 것이니 규격에 대한 설명은 생략하도록 하겠습니다. 요지는 JSON으로 동일한 속성을 가진 여러벌의 JSON 데이터가 나온다는 점입니다. 2021년 7월의 전세자금대출 정보를 쿼리해보니 은행별로 최저, 최대 금리가 나오고 대출 횟수가 같이 나옵니다. 

curl로 기본적인 GET 요청을 던졌고 돌아오는 응답을 파이프로 연결하여 jq '.' 로 넘겨보았습니다. 이렇게 하는 것 만으로 아래와 같이 두가지 극단적인 결과를 볼 수 있습니다. jq를 써보신 분들은 다 아시고, jq를 처음 쓴다면 일단 외워두는 것이 jq '.' 입니다. 

아.. 머리가 아프다...
단지 jq '.' 를 파이프로 연결했을 뿐인데...

 

// 머리아픈 JSON보기
curl -v "http://apis.data.go.kr/B551408/rent-loan-rate-multi-dimensional-info/dimensional-list?serviceKey=##공공데이터포털에서_키를받아_넣으세요!##&loanYm=202105&cbGrd=1&debt=11&numOfRows=5&pageNo=1&dataType=json"

// 속시원한 JSON보기
curl -v "http://apis.data.go.kr/B551408/rent-loan-rate-multi-dimensional-info/dimensional-list?serviceKey=##공공데이터포털에서_키를받아_넣으세요!##&loanYm=202105&cbGrd=1&debt=11&numOfRows=5&pageNo=1&dataType=json" | jq '.'

 

특정 아이템만 뽑아내보자

jq '.'를 사용해서 사람이 읽기 좋은 포맷을 쉽게 만들어 보았습니다. 하지만 데이터가 많다면 이 데이터를 한 번 더 필터링 해서 원하는 정보만 발라내서 보고 싶어지기 마련입니다. 

JSON의 구조를 잘 보니 최상위 속성으로 "header"와 "body"가 눈에 띕니다. "header"는 API 호출에 대한 처리 결과를 담고 있으니 우리에겐 중요하지 않습니다. 우리는 두번째 속성인 "body"의 내용에 관심이 있습니다. "body"의 하위 JSON만 뽑아내려면 어떻게 해야 할까요?

jq '.body'

// jq '.body' 로 파이프를 거세요!
curl -v "http://apis.data.go.kr/B551408/rent-loan-rate-multi-dimensional-info/dimensional-list?serviceKey=##공공데이터포털에서_키를받아_넣으세요!##&loanYm=202105&cbGrd=1&debt=11&numOfRows=5&pageNo=1&dataType=json" | jq '.body'

앞서 사용했던 jq 명령을 조금 더 진화시켜서 jq '.body'를 했더니 특정한 속성 하위의 JSON만 출력할 수 있었습니다. 참 쉽죠? 이쯤되면 조금 더 욕심이 나실겁니다. 잘 보니 "items"라는 배열 하위에 찐 정보들이 가득합니다. 과감하게 jq '.body.items'를 하면 원하는 값이 나오겠죠?

jq '.body.items'

 

반복되는 JSON에서 특정 속성만 뽑아내기

자 그런데 여전히 뭔가 번잡해 보입니다. 금융 서비스나 핀테크 서비스를 만든다면 사용자들에게 특정 은행의 전세자금대출 상품 소개를 하면서 최저금리를 안내해서 클릭을 유도하고 싶을 수 있습니다. 그렇다면 최소 금리를 나타내는 항목인 "minLoanRat"만 뽑아서 보면 좋을 것 같다는 생각이 듭니다. jq '.body.items.minLoanRat'을 하면 될 것 같죠?

jq '.body.items.minLoanRa' 은 에러입니다!!

하지만 결과는 제대로 나오지 않고 만나고 싶지 않았던 에러 메세지를 맞딱드렸습니다. 뭐가 문제일까요? 그것은 바로 앞선 jq '.body.items'의 결과가 배열이기 때문입니다. 배열은 인덱스라는 순서가 존재합니다. 이를 나타내기 위해서는 []를 써야 합니다. jq '.body.items[].minLoanRat'으로 명령을 바꿔서 시도해보겠습니다!

jq '.body.items[].minLoanRat'

결과가 잘 나왔습니다! 하지만 뭔가 아쉽습니다. 도대체 어느 은행에서 이 금액으로 대출을 해준건지 도통 알수가 없는 상태이기 때문이죠. 은행의 이름도 분명 원래의 JSON 데이터에 있었는데... 이걸 jq 로 함께 뽑아서 < "은행": #최소대출금리# >의 형태로 볼 수 있다면 얼마나 좋을까요?

 

반복되는 JSON을 조작하여 새로운 JSON 만들어내기

jq는 여러분을 위해 이미 그렇게 할 수 있는 방법을 준비해 두었습니다. jq는 curl과 같은 다른 명령으로부터 JSON 데이터를 파이프(|)로 전달 받을 수 있는 것은 물론이고, 자신이 스스로 데이터를 몇 번씩 가공하여 파이프로 연결해서 가공할 수 있습니다. 우리가 원하는 결과를 만들기 위해서는 아래와 같은 jq 연산을 해볼 수 있습니다.

jq '.body.items[] | { bankNm, avgLoanRat }'

jq '.body.items[] { bankNm, avgLoanRat }'

드디어 완성이 된 것 같습니다. 하지만 약간 더 손을 보면 다른 어플리케이션에서 데이터를 다루기 더 쉬워질 수 있습니다. 위 그림에서의 JSON은 JSON의 규격 위반으로 다른 프로그램에서 JSON으로 파싱할때 에러가 발생합니다. 각 항목이 콤마로 연결되어야 하고 배열이기 때문에 []로 묶일 필요가 있습니다. 

jq '[ .body.items[] | { bankNm, avgLoanRat } ]'

전체를 []로 묶어주니 자동으로 각 항목과 항목 사이를 콤마로 연결해 주어 완성된 JSON의 형태를 만들어 주었습니다. 이렇게 만들어진 JSON이 정말 문제 없는지 jsonlint.com 에서 검증을 해보았습니다. 네, 역시 문제 없네요!

 


이번 포스팅에서는 jq 를 이용하여 간단하게 데이터를 조작하는 방법을 살펴보았습니다. 다음 포스팅에서는 조건문을 활용하여 jq 를 보다 어렵게(?) 사용하는 방법을 살펴보도록 하겠습니다.

728x90
728x90

HTTP/2 시대가 시작되면서 다양한 성능 개선을 위한 사례들을 요즘 찾아보고 있습니다. QUIC 도 그중 하나이고 TCP Fast Open 이라는 표준 역시 살펴봐야 할 사례인 것 같습니다. 공부할 건 많고 시간은 없고 머리는 안돌아가고... 그래도 일단 필요한 링크들을 모아봅니다. 먼저 공부하시는 분들이 계시다면 정리해서 공유를... 굽신...


# TCP Fast Open - TCP 의 3 way handshake 로 발생하는 RTT 및 Latency 의 한계를 극복하려는 노력 / Handshake 할때부터 컨텐츠를 담아 전달해 보자는 것이 요지.



출처 : 구글 기술문서 (아래의 링크5)



링크1 - RFC 7413 - TCP Fast Open (Experimental) : https://tools.ietf.org/html/rfc7413

링크2 - Cent OS 7 + nginx 환경에서 TCP Fast Open 활성화 하기 : https://goo.gl/pRmWZO

링크3 - TCP Fast Open 위키피디가 : https://en.wikipedia.org/wiki/TCP_Fast_Open

링크4 - curl 7.49.0 의 특정 운영체제 버전에서 옵션 제공 : https://curl.haxx.se/libcurl/c/CURLOPT_TCP_FASTOPEN.html

링크5 - 구글에서 발표된 기술 문서 : http://goo.gl/rz1sqX

링크6 - Keycdn 의 아티클 (일종의 요약) : https://www.keycdn.com/support/tcp-fast-open/


- NoPD -

728x90
728x90

웹 컨텐츠 전송을 위한 프로토콜의 대세가 h2 혹은 http/2 로 자리잡아 가면서 맥(Mac)의 쉘에서도 http/2를 테스트 해야하시는 분들이 많이 늘었을 것으로 생각됩니다. 알려진 내용에 따르면 curl 의 7.34.1 버전 이후에는 --http2 옵션을 통해 http2 로 서버와 통신을 하도록 강제할 수 있지만 환경에 따라서 안되는 경우가 많습니다. curl 은 http/2 를 지원하기 위해 nghttp2 라이브러리를 이용하고 있기 때문에 우선은 nghttp2 를 설치해야 합니다.




nghttp2 가 설치되면 이를 이용해서 curl 을 다시 build 하거나 설치해야 합니다. 홈브루(Homebrew)를 이용하면 간단하게 새로운 버전으로 빌드를 하면서 설치할 수 있으니 아래의 커맨드를 참고해서 설치를 진행하도록 합시다. 아래와 같이 설치한 후 brew info curl 명령을 통해 nghttp2 에 초록색 체크박스가 잘 들어왔다면 일단 설치는 제대로 잘 된거라 봐도 되겠습니다.





그런데 여기까지 하고나서도 curl 을 --http2 옵션으로 실행했을 때 지원하지 않는 프로토콜이라고 에러가 떨어진다면 심볼릭 링크를 한번 교체해줄 필요가 있습니다. 환경 설정에 따라, 사용자 계정에 따라 sudo 를 통해서 권한 상승을 해야 할 필요도 있으니 상황에 따라 적절한 옵션으로 심볼릭 링크를 교체해 주시면 되겠습니다. 




여기까지 해서 마무리가 잘 되었다면 curl --http2 옵션으로 http2 가 활성화된 사이트들, 예를 들어서 아카마이의 https://http2.akamai.com 이라던가 구글 메인 페이지 (https://www.google.com) 쪽으로 요청을 던져볼 수 있게 되셨을 겁니다. 일단 개인적으로 여기까지 해서 문제는 없었습니다만 다른 문제를 겪는 분이 계시다면 댓글로 남겨주시면 한번 살펴보도록 하겠습니다!



- NoPD -




728x90

+ Recent posts