웹 클라이언트
서버에게 무언가를 달라고 하는 모든 것.
브라우저도 curl 한 줄도 웹 클라이언트예요. nc 로 HTTP 요청을 손으로 써 본 뒤, curl 과 Chrome 개발자 도구로 같은 글이 오가는 것을 확인해 보세요.
먼저 묻는 쪽이 클라이언트입니다
와 서버는 기계가 아니라 역할입니다. 말을 먼저 걸어 무언가를 달라고 하는 쪽이 클라이언트이고, 기다렸다가 답하는 쪽이 서버입니다. 브라우저도 클라이언트, curl 도 클라이언트, 휴대폰 앱도, 를 부르는 다른 서버도 클라이언트입니다.
그래서 웹 클라이언트를 한 줄로 쓸 수 있습니다. 창도, 도, 마우스도 필요 없습니다 — 연결하고, 을 보내고, 돌아온 것을 읽으면 됩니다.
| 무엇이 | 클라이언트 | 서버 |
|---|---|---|
| 누가 먼저 말하나 | 연결을 열고 요청을 보냅니다. | 에서 기다립니다. 누가 연결할 때까지 말이 없습니다. |
| 누가 주소가 필요한가 | 서버가 어디 있는지 알아야 합니다 — 이나 , 그리고 포트. | 변하지 않는 주소가 있어야 합니다. 서버가 도메인 이름을 갖고 클라이언트는 대개 갖지 않는 이유입니다. |
| 한 번에 몇이나 | 보통은 한 번에 한 대화입니다. 다만 브라우저는 페이지를 빨리 불러오려고 여러 개를 함께 엽니다. | 한꺼번에 여럿입니다. 진짜 서버 가 복잡해지는 이유의 대부분이 여기 있습니다. |
지도를 받아 오거나 카드를 긁는 웹서버는 그 요청에서는 클라이언트로 행동합니다. 역할은 순식간에 바뀌므로, 양쪽 끝에 어떤 기계가 있느냐가 아니라 지금 이 요청이 어느 방향으로 가느냐를 물어야 합니다.
터미널로 웹 클라이언트 만들기
가 글자일 뿐이라는 것을 가장 빨리 믿는 방법은 을 직접 쳐 보는 것입니다. 앞 주제의 웹서버를 띄워 놓고, 을 하나 더 열어 손으로 말을 걸어 보세요.
nc 로 요청을 손으로 쓰기
은 에 연결해 여러분이 친 글자를 그대로 선에 흘려보냅니다. 두 줄을 치고 엔터를 두 번 누르면 서버가 답합니다 — 방금 브라우저의 일을 손으로 한 것입니다.
# connect, then type the two lines below and press Enter once more
nc localhost 8084
GET / HTTP/1.1
Host: localhost
# or send it all at once (printf's \r\n is HTTP's line break;
# sleep keeps the line open a moment so the shell server can answer)
{ printf 'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n'; sleep 1; } | nc localhost 8084
- 끝의 이 중요합니다. 요청이 끝났다고 서버에게 알리는 표시이고, 그래서 엔터를 한 번 더 누릅니다.
- HTTP 는 줄 끝마다 과 을 요구합니다. 손으로 쳐도 되는 것은 대개의 서버가 너그럽기 때문이고, 판은 이 요구하는 그대로를 보냅니다.
- 줄은 이 반드시 요구합니다. 진짜 사이트에 이것 없이 보내면 페이지 대신 오류가 돌아오는 것이 보통입니다.
스크립트로 감싸기
요청이 printf 한 줄이 되고 나면, 다시 쓸 수 있는 는 몇 줄이면 됩니다. 아래 는 · 포트 · 를 받아 요청을 보내고, 와 을 갈라 보여 줍니다.
#!/bin/bash
# usage: bash client.sh localhost 8084 /
HOST=${1:-localhost}
PORT=${2:-8084}
PATH_=${3:-/}
{ printf 'GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n' "$PATH_" "$HOST"; sleep 1; } \
| nc "$HOST" "$PORT" \
| tr -d '\r' \
| awk 'BODY { print; next } /^$/ { BODY = 1; next } { print "[header] " $0 }'
은 HTTP 가 줄 끝마다 남기는 캐리지리턴을 걷어 내고, 는 빈 줄을 만날 때까지를 헤더로 표시합니다 — 그 뒤는 전부 본문입니다. 브라우저가 화면을 그리기 전에 하는 것과 똑같은 나눔입니다.
한 터미널에 쉘 웹서버를, 다른 터미널에 이 클라이언트를 띄우면 여러분이 직접 쓴 대화의 양쪽 끝을 모두 갖게 됩니다. 쉘 웹서버에 보낼 때는 위 처럼 으로 연결을 잠깐 열어 두어야 답을 받습니다. 서버의 을 고치면 클라이언트가 곧바로 알아봅니다 — 사이에 아무것도 없기 때문입니다.
curl — 매일 쓰게 될 클라이언트
우리 스크립트가 대충 하던 것을 curl 은 제대로 합니다. , , , 업로드, , 까지. 거의 모든 기계에 들어 있고, 브라우저를 끼우지 않고 서버를 확인하는 표준 방법입니다.
# body only
curl http://localhost:8084
# body plus the response headers
curl -i http://localhost:8084
# the whole exchange, request headers included
curl -v http://localhost:8084
중요한 옵션들
| 옵션 | 하는 일 |
|---|---|
-i | 과 함께 헤더도 보여 줍니다. 페이지가 예상과 다를 때 가장 먼저 붙이는 옵션입니다. |
-v | 자세히 보기. 보낸 과 받은 응답을 연결 과정까지 한 줄씩 보여 줍니다. |
-L | 리다이렉트를 따라갑니다. 없으면 이 왔을 때 원하던 페이지 대신 거의 빈 응답을 받게 됩니다. |
-o FILE | 응답을 화면에 뿌리지 않고 파일로 저장합니다. curl 을 내려받기 도구로 쓰는 방식입니다. |
-H "Name: value" | 요청 헤더를 더합니다 — 내용의 종류, , 원하는 언어 같은 것들. |
-d "data" | 묻기만 하지 않고 자료를 보냅니다. -d 만 붙여도 가 되고(다른 방식은 -X 로 고릅니다), 에서 양식이나 를 시험하는 방법이 이것입니다. |
-s | 조용히. 진행 막대를 없앱니다. 출력을 다른 명령이나 스크립트로 넘길 때는 늘 붙입니다. |
-A "name" | 특정 브라우저인 척합니다. 어떤 사이트는 묻는 쪽이 누구냐에 따라 다르게 답합니다. |
API 호출하기
요즘 앱이 말을 거는 상대는 페이지가 아니라 을 돌려주는 API 인 경우가 많습니다. curl 이 그것을 받아 오고 jq 가 읽기 좋게 다듬습니다. 응용 를 한 줄도 쓰기 전에 를 확인하는 방법입니다.
# fetch JSON and pick one field out of it with jq
curl -s https://api.github.com/repos/sveltejs/svelte | jq '.stargazers_count'
# send JSON with POST
curl -X POST https://httpbin.org/post \
-H 'Content-Type: application/json' \
-d '{"name":"SONUB","level":1}'
# download to a file
curl -L -o page.html https://sonub.com
무엇이든 curl 로 먼저 시험하는 버릇을 들이세요. curl 이 제대로 된 답을 받으면 서버는 멀쩡하고, 잘못은 내 에 있습니다. curl 도 이상한 답을 받으면 서버 쪽 문제입니다 — 엉뚱한 곳을 뒤지며 반나절을 버리지 않아도 됩니다.
Chrome 도 같은 클라이언트, 크기만 다를 뿐
은 여러분이 로 보낸 그 을 보냅니다. 그러고 나서 돌아온 답을 사람이 볼 수 있는 화면으로 바꾸는 어마어마한 일을 더 합니다 — 진짜 차이는 그 "더" 뿐입니다.
그 단계들을 알아 둘 값어치가 있습니다. 하나하나가 페이지가 어긋날 수 있는 자리이기 때문입니다. 무언가 안 보일 때 물어야 할 것은 언제나 "어느 단계에서 실패했는가" 입니다.
주소창에서 그림까지
- 이름 풀기 가 이름을 로 바꿉니다. 여기서 실패하면 서버에 닿아 보지도 못하고, 도 페이지가 아니라 이름을 가리킵니다.
- 연결하고 안전하게 만들기연결을 열고, 라면 무엇을 보내기도 전에 를 확인합니다. 여기서 나오는 경고는 페이지가 없다는 뜻이 아니라 를 믿을 수 없다는 뜻입니다.
- 요청 보내기여러분이 손으로 친 것과 같은 몇 줄에 가 훨씬 많이 붙습니다. , 읽을 수 있는 형식, 좋아하는 언어 같은 것들입니다.
- 나머지 받아 오기 을 읽어 로 를 세웁니다. 그리고 페이지가 가리키는 것을 모두 요청합니다. 스타일 파일·그림·글꼴·스크립트를 보통 여러 개 한꺼번에 받습니다.
- 꾸미고, 배치하고, 그리기 를 입히고, 상자마다 자리를 계산해 그립니다. 는 HTML 을 읽는 도중에도 돌고, 그린 뒤에도 화면을 다시 바꿀 수 있습니다.
터미널 클라이언트냐 브라우저냐
Chrome · · · 는 모두 위에 지어졌으므로, 하나에서 되는 페이지는 대개 나머지에서도 됩니다. 와 는 다른 엔진을 씁니다. 사이트를 다 만들었다고 말하기 전에 최소한 두 종류에서 열어 봐야 하는 이유가 그것입니다.
개발자 도구 — 오가는 글을 눈으로 보기
에는 웹 도구가 들어 있고, 이미 설치되어 있습니다. 로 손수 보내던 것이 여기에 하나하나로, 그 옆에 까지 함께 늘어섭니다.
를 누르거나, 는 Command-Option-I, 그 밖에서는 Control-Shift-I 입니다. 페이지의 아무 곳이나 오른쪽 눌러 [검사]를 고르면 그 가 이미 선택된 채로 열립니다 — 가장 빠른 입구입니다.
패널들
지금 바로 해 볼 세 가지
- 내 요청 찾아보기을 열고 이 페이지를 새로고침한 뒤 맨 첫 항목을 눌러 보세요. 거기 있는 요청·응답 가 여러분이 nc 에 쳐 넣던 줄과 같은 내용입니다. 로 연결된 사이트에서는 첫 줄과 가 ·:path·:authority 라는 이름으로 보입니다.
- curl 로 복사하기요청을 오른쪽 눌러 [Copy as cURL] 을 고르고 에 붙여 넣으세요. 헤더도 쿠키도 그대로, 브라우저가 한 일을 똑같이 한 것입니다.
- 일부러 망가뜨려 보기에서 제목을 지워 사라지는 것을 보고, Network 에서 속도를 느리게 조절한 뒤 새로고침해 보세요. 둘 다 안전하고, 둘 다 글로 읽는 것보다 훨씬 많이 가르쳐 줍니다.
첫 주제에서 만든 HTML 파일을 열어 검사해 보면 나무 속의 태그가 전부 눈에 익을 것입니다. 쓰고 · 내놓고 · 요청하고 · 들여다보는 이 한 바퀴가 웹 개발 전체의 축소판입니다.
스스로 표시하는 칸이에요. 여기서 채점하지는 않아요.
이 단계를 이해한 것으로 표시할까요?
아직 취소할 수 없으니, 정말 이해했을 때만 표시해 주세요.
이해한 것으로 표시했어요
스스로 표시하는 칸이에요. 여기서 채점하지는 않아요.