수학과의 좌충우돌 프로그래밍

[Web] 사용자 친화적인 http client, Httpie 본문

웹프로그래밍

[Web] 사용자 친화적인 http client, Httpie

ssung.k 2019. 8. 4. 19:07

우리는 직접 웹사이트에 들어가지 않고도 정보를 얻을 수 있습니다. CLI 를 통해 명령어를 입력하는 것으로만으로 말이죠. 앞으로 공부할 django restful API 처럼 API 를 테스트 하는데도 사용할 수 있습니다.

기존에는 cURL 을 많이 사용한 듯한데 최근에는 사용이 더 쉬운 httpie 가 더 선호되고 있습니다. 그래서 httpie 에 대해서 알아보도록 하겠습니다.

 

Httpie 란?

Httpie 는 CLI HTTP 클라이언트 입니다. 다른 HTTP 클라이언트가 무엇이 있을까요? 우리가 일반적으로 사용하는 웹 브라우저가 가장 대표적인 클라이언트라고 할 수 있겠습니다. 서두에서 말한대로 웹 사이트, 즉 웹 브라우저를 통해 들어가지 않고도 Httpie 라는 다른 클라이언트를 통해서 같은 정보를 얻어 올 수 있는 것이죠. 그 과정에서 단순하고 자연스러운 문법을 사용하고 결과를 하이라이트를 통해 사용자에게 제공해줌으로서 인간 친화성을 방향으로 삼고 있습니다.

 

Httpie 설치하기

Httpie 공식 홈페이지 에서 online 으로도 테스트 해볼 수 있지만 로컬에서 설치해서 사용해보도록 하겠습니다.

설치 명령어는 pip 를 통해서 진행합니다.

pip install --upgrade httpie

 

Httpie 명령어

Httpie 명령어는 다음과 같은 기본꼴을 가집니다.

http [flags] [METHOD] URL [ITEM [ITEM]]

각각에 대해서 하나씩 알아보도록 합시다.

  • http

    시작은 항상 http 로 합니다.

  • flags

    옵션의 역할을 합니다. 옵션은 너무 다양한 옵션들이 있어서 뒤에서 실습을 통해 몇 가지 알아보도록 하겠습니다.

  • method

    HTTP 메소드를 설정하며 생략할 경우 자동으로 GET 방식으로 보냅니다.

  • URL

    연결할 URL 을 선택합니다.

  • ITEM [ITEM]

    어떤 값을 넘겨 줄 수 있는 인자로서 역할을 합니다.

    POST, PUT 방식으로 요청을 할 때는 = 으로서, GET 방식으로 요청을 == 로서 표현을 합니다.

 

Httpie 실습하기

예시로 사용할 url 로는http://example.com/ 을 사용하도록 하겠습니다. 링크로 들어가보시면 알겠지만, 허가가 없어도 자유롭게 해당 도메인을 예제로 사용이 가능합니다.

해당 url 에 대해서 get 요청을 보내면,

http get "example.com"

다음과 같은 정보를 얻을 수 있습니다.

HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Encoding: gzip
Content-Length: 606
Content-Type: text/html; charset=UTF-8
Date: Sun, 04 Aug 2019 08:26:40 GMT
Etag: "1541025663+gzip"
Expires: Sun, 11 Aug 2019 08:26:40 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (sec/9795)
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
        
    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 50px;
        background-color: #fff;
        border-radius: 1em;
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        body {
            background-color: #fff;
        }
        div {
            width: auto;
            margin: 0 auto;
            border-radius: 0;
            padding: 1em;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is established to be used for illustrative examples in documents. You may use this
    domain in examples without prior coordination or asking for permission.</p>
    <p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

 rkdalstjd9@arkui-MacBook-Pro  ~  http get "example.com"
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Encoding: gzip
Content-Length: 606
Content-Type: text/html; charset=UTF-8
Date: Sun, 04 Aug 2019 08:28:22 GMT
Etag: "1541025663"
Expires: Sun, 11 Aug 2019 08:28:22 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (sec/96EE)
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
        
    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 50px;
        background-color: #fff;
        border-radius: 1em;
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        body {
            background-color: #fff;
        }
        div {
            width: auto;
            margin: 0 auto;
            border-radius: 0;
            padding: 1em;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is established to be used for illustrative examples in documents. You may use this
    domain in examples without prior coordination or asking for permission.</p>
    <p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

위 쪽에는 응답헤더가, 그 이후에는 이에 해당하는 html 과 css 파일의 내용이 넘어오게 됩니다.

너무 길기 때문에 header 만을 확인해야 할 경우에는 옵션으로 header 만 지정해줄 수 있습니다. get 은 생략가능하므로 생략해주었습니다.

http --header "example.com"

위와 똑같은 내용의 header 가 출력되는 걸 확인할 수 있습니다.

HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Encoding: gzip
Content-Length: 606
Content-Type: text/html; charset=UTF-8
Date: Sun, 04 Aug 2019 08:32:30 GMT
Etag: "1541025663+gzip"
Expires: Sun, 11 Aug 2019 08:32:30 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (sec/976A)
Vary: Accept-Encoding
X-Cache: HIT

 

그렇다면 httpie 를 통해서 글을 쓰는 것도 가능할까요?

제가 만든 간단한 장고서버에서 실행을 해보았습니다.

http --form post "http://127.0.0.1:8000/post_create/" title="title" content="content"

form을 통해서 글을 작성하기 때문에 옵션으로 지정해주고, 글을 작성하는 method 는 post 입니다. 그리고 글을 작성하는 url 과 그에 따른 제목과 내용에 해당하는 인자까지 같이 넘겨주었습니다.

하지만 결과는 실패입니다. csrf_token 이 없다는 이유로 에러를 발생합니다. 장고 자체적으로 보안의 문제로 인해서 이를 막고 있습니다. 글을 쓰는 것 외에도 글 삭제, 수정 등도 마찬가지로 거부 당하게 됩니다.

 

 

다음으로는 https://httpbin.org/ 을 사용해서 실습을 진행해보도록 하겠습니다. 이는 HTTP Request & Response 를 테스트 하기 위해 만들어진 서버로, url 뒤에 method 를 추가해서 사용할 수 있습니다.

get 방식으로 두 인자 a,b 를 넘겨 보았습니다.

http "httpbin.org/get" a==1 b==2

args 에 해당 데이터가 전달되었음을 확인할 수 있습니다.

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 192
Content-Type: application/json
Date: Sun, 04 Aug 2019 09:44:40 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
    "args": {
        "a": "1",
        "b": "2"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/1.0.2"
    },
    "origin": "58.232.15.61, 58.232.15.61",
    "url": "https://httpbin.org/get?a=1&b=2"
}

 

post 방식에 대해서 form 과 json 두 가지 방법으로 a,b 를 넘겨본 결과,

http --form post "httpbin.org/post" a=1 b=2

form 에 데이터가 담기고,

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 271
Content-Type: application/json
Date: Sun, 04 Aug 2019 09:51:14 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
    "args": {},
    "data": "",
    "files": {},
    "form": {
        "a": "1",
        "b": "2"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "7",
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/1.0.2"
    },
    "json": null,
    "origin": "58.232.15.61, 58.232.15.61",
    "url": "https://httpbin.org/post"
}

 

json 에 데이터가 담기는 것을 확인할 수 있습니다.

http --json post "httpbin.org/post" a=1 b=2

json 으로 데이터를 넘길 경우에는 data 에 문자열로서 데이터가 함께 전달됩니다.

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 263
Content-Type: application/json
Date: Sun, 04 Aug 2019 09:52:56 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
    "args": {},
    "data": "{\"a\": \"1\", \"b\": \"2\"}",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "application/json, */*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "20",
        "Content-Type": "application/json",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/1.0.2"
    },
    "json": {
        "a": "1",
        "b": "2"
    },
    "origin": "58.232.15.61, 58.232.15.61",
    "url": "https://httpbin.org/post"
}

 

 

 

Comments