[翻訳] httr vignette: httrはやわかり

この文書は Hadley Wickham によるRパッケージ[`httr`](https://cran.r-project.org/web/packages/httr/) (version 1.1.0) のビネット "[httr quickstart guide](https://cran.r-project.org/web/packages/httr/vignettes/quickstart.html)" の翻訳です．
License: [MIT](https://opensource.org/licenses/MIT)

* 関連記事：[APIパッケージ作成のベストプラクティス](http://qiita.com/nakamichi/items/64d1332f4137046e518a)
  
---

<!-- # httr quickstart guide -->
httrはやわかり
--------------------

<!-- The goal of this document is to get you up and running with httr as quickly as possible. httr is designed to map closely to the underlying http protocol. I'll try and explain the basics in this intro, but I'd also recommend "[HTTP: The Protocol Every Web Developer Must Know][http-tutorial]" or "[HTTP made really easy](http://www.jmarshall.com/easy/http/)". -->

この文書の目的は，読者にhttrをできるだけすぐに使い始められるようになってもらうことです．httrは，基礎となっているHTTPプロトコルと密接に対応するように設計されています．この入門編でもHTTPの基本的な事柄は説明するように努めますが，"[HTTP: The Protocol Every Web Developer Must Know][http-tutorial]"や"[HTTP made reallyeasy](http://www.jmarshall.com/easy/http/)"も読むことを推奨します．

<!-- This vignette (and parts of the httr API) derived from the excellent "[Requests quickstart guide](http://docs.python-requests.org/en/latest/user/quickstart/)" by Kenneth Reitz. Requests is a python library similar in spirit to httr.   -->

このビネット（とhttr APIの一部）は，Kenneth Reitzによる素晴らしい"[Requests quickstart guide](http://docs.python-requests.org/en/latest/user/quickstart/)"の派生版です．Requestsはhttrと同様の設計思想に基づくPythonライブラリです．

<!-- There are two important parts to http: the __request__, the data sent to the server, and the __response__, the data sent back from the server. In the first section, you'll learn about the basics of constructing a requests and accessing the response. In the second and third sections, you'll dive into more details of each. -->

HTTPには2つの重要なパーツがあります．ひとつは**リクエスト**で，サーバに送られるデータのことです．もうひとつは**レスポンス**で，こちらはサーバから送り返されるデータのことです．最初のセクションでは，リクエストの作成とレスポンスへのアクセスの基本を学びます．2つ目と3つ目のセクションでは，リクエストとレスポンスそれぞれの詳細に踏み込んでいきます．

<!-- ## httr basics -->
## httrの基本

<!-- To make a request, first load httr, then call `GET()` with a url: -->
リクエストを作成するには，まずhttrをロードし，次に`GET()`にURLを与えて呼び出します：


```r
library(httr)
r <- GET("http://httpbin.org/get")
```

<!-- This gives you a response object. Printing a response object gives you some useful information: the actual url used (after any redirects), the http status, the file (content) type, the size, and if it's a text file, the first few lines of output. -->
するとレスポンスオブジェクトが返ってきます．レスポンスオブジェクトを表示するといくつかの有益な情報が得られます．（リダイレクトの後に）実際に使われたURLや，HTTPステータス，ファイル（コンテンツ）のタイプ，サイズなどです．コンテンツがテキストファイルであれば，その最初の数行も表示されます．


```r
r
#> Response [http://httpbin.org/get]
#>   Date: 2016-03-20 18:02
#>   Status: 200
#>   Content-Type: application/json
#>   Size: 300 B
#> No encoding supplied: defaulting to UTF-8.
#> {
#>   "args": {}, 
#>   "headers": {
#>     "Accept": "application/json, text/xml, application/xml, */*", 
#>     "Accept-Encoding": "gzip, deflate", 
#>     "Host": "httpbin.org", 
#>     "User-Agent": "libcurl/7.43.0 r-curl/0.9.6 httr/1.1.0"
#>   }, 
#>   "origin": "119.104.43.128", 
#>   "url": "http://httpbin.org/get"
#> ...
```

<!-- You can pull out important parts of the response with various helper methods, or dig directly into the object: -->
色々なヘルパメソッドを使うことで，レスポンスから重要な箇所を抜き出すことができます．リクエストオブジェクトの中身を直接触ってもかまいません：


```r
status_code(r)
#> [1] 200
headers(r)
#> $server
#> [1] "nginx"
#> 
#> $date
#> [1] "Sun, 20 Mar 2016 18:02:49 GMT"
#> 
#> $`content-type`
#> [1] "application/json"
#> 
#> $`content-length`
#> [1] "300"
#> 
#> $connection
#> [1] "keep-alive"
#> 
#> $`access-control-allow-origin`
#> [1] "*"
#> 
#> $`access-control-allow-credentials`
#> [1] "true"
#> 
#> attr(,"class")
#> [1] "insensitive" "list"
str(content(r))
#> List of 4
#>  $ args   : Named list()
#>  $ headers:List of 4
#>   ..$ Accept         : chr "application/json, text/xml, application/xml, */*"
#>   ..$ Accept-Encoding: chr "gzip, deflate"
#>   ..$ Host           : chr "httpbin.org"
#>   ..$ User-Agent     : chr "libcurl/7.43.0 r-curl/0.9.6 httr/1.1.0"
#>  $ origin : chr "119.104.43.128"
#>  $ url    : chr "http://httpbin.org/get"
```

<!-- I'll use `httpbin.org` throughout this introduction. It accepts many types of http request and returns json that describes the data that it recieved. This makes it easy to see what httr is doing. -->
この入門編の全体に渡って`httpbin.org`を利用します．ここは様々なタイプのHTTPリクエストを受け付けて，受け取ったデータを記述するJSONを返してくれるので，httrが何をやっているのかが容易に理解できます．

<!-- As well as `GET()`, you can also use the `HEAD()`, `POST()`, `PATCH()`, `PUT()` and `DELETE()` verbs. You're probably most familiar with `GET()` and `POST()`: `GET()` is used by your browser when requesting a page, and `POST()` is (usually) used when submitting a form to a server. `PUT()`, `PATCH()` and `DELETE()` are used most often by web APIs. -->
`GET()`の他にも`HEAD()`, `POST()`, `PATCH()`, `PUT()`，`DELETE()`という動詞を使うことができます．おそらく`GET()`と`POST()`にいちばん馴染みがあるでしょう．`GET()`はブラウザがページをリクエストするときに使われるもので，`POST()`は（大抵は）フォームをサーバに投稿するときに使われます．`PUT()`，`PATCH()`，`DELETE()`はweb APIによって使われることが多いです．

<!-- ## The response  -->
## レスポンス

<!-- The data sent back from the server consists of three parts: the status line, the headers and the body. The most important part of the status line is the http status code: it tells you whether or not the request was successful. I'll show you how to access that data, then how to access the body and headers. -->
サーバから送り返されてくるデータは3つのパーツで構成されています．ステータス行とヘッダとボディです．ステータス行でいちばん重要な部分はHTTPステータスコードです．これによってリクエストが成功したかどうかがわかります．以下ではステータスコードにアクセスする方法を示し，それからボディとヘッダにアクセスする方法を示します．


<!-- ### The status code -->
### ステータスコード

<!-- The status code is a three digit number that summarises whether or not the request was succesful (as defined by the server that you're talking to). You can access the status code along with a descriptive message using `http_status()`: -->
ステータスコードはリクエストが成功したかどうかを要約した3桁の番号です（通信しているサーバによって定義されます）．ステータスコードと，その内容を記述したメッセージには，`http_status()`関数でアクセスできます：


```r
r <- GET("http://httpbin.org/get")
# 役に立つ情報を取得する:
http_status(r)
#> $category
#> [1] "Success"
#> 
#> $reason
#> [1] "OK"
#> 
#> $message
#> [1] "Success: (200) OK"

# または単なるコード値を取得する:
r$status_code
#> [1] 200
```

<!-- A succesful request always returns a status of 200. Common errors are 404 (file not found) and 403 (permission denied). If you're talking to web APIs you might also see 500, which is a generic failure code (and thus not very helpful). If you'd like to learn more, the most memorable guides are the [http status cats](https://www.flickr.com/photos/girliemac/sets/72157628409467125). -->
成功したリクエストは常にステータス200を返します．よくあるエラーは404（file not found）と403（permission denied）です．web APIを利用している場合は，コード500を見ることもあるかもしれません．このコードは失敗一般を表しています（なので，それほど役立つ情報ではありません）．ステータスコードについてもっと知りたい場合，最も覚えやすいガイドは[http status cats](https://www.flickr.com/photos/girliemac/sets/72157628409467125)です．

<!-- You can automatically throw a warning or raise an error if a request did not succeed: -->
リクエストが成功しなかった場合には自動的にエラーや警告を出すようにできます：


```r
warn_for_status(r)
stop_for_status(r)
```

<!-- I highly recommend using one of these functions whenever you're using httr inside a function (i.e. not interactively) to make sure you find out about errors as soon as possible. -->
httrを関数の中で使用する場合（つまり，インタラクティブに使うのではない場合）には，可能な限り早くエラーに気付けるようにするために，常にこれらの関数のいずれかを使うことを強く推奨します

<!-- ### The body -->
### ボディ

<!-- There are three ways to access the body of the request, all using `content()`: -->
リクエストのボディにアクセスする方法は3種類ありますが，いずれも`content()`関数を使用します：

<!-- * `content(r, "text")` accesses the body as a character vector: -->
*  `content(r, "text")` はボディに文字型ベクトルとしてアクセスします:

    
    ```r
    r <- GET("http://httpbin.org/get")
    content(r, "text")
    #> No encoding supplied: defaulting to UTF-8.
    #> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.43.0 r-curl/0.9.6 httr/1.1.0\"\n  }, \n  \"origin\": \"119.104.43.128\", \n  \"url\": \"http://httpbin.org/get\"\n}\n"
    ```

    <!-- httr will automatically decode content from the server using the encoding  -->
    <!-- supplied in the `content-type` HTTP header. Unfortunately you can't always  -->
    <!-- trust what the server tells you, so you can override encoding if needed: -->
    httrは`content-type` HTTPヘッダで与えられたエンコーディングを使用して，サーバから返されたコンテンツを自動的にデコードします．残念なことに，サーバの言うことが常に信頼できるとは限らないので，必要であればエンコーディングは上書きすることができます：

    
    ```r
    content(r, "text", encoding = "ISO-8859-1")
    ```

    <!-- If you're having problems figuring out what the correct encoding  -->
    <!-- should be, try `stringi::stri_enc_detect(content(r, "raw"))`. -->
    正しいエンコーディングが何なのか見当が付かない場合は，`stringi::stri_enc_detect(content(r, "raw"))`を試してみてください．

<!-- *   For non-text requests, you can access the body of the request as a  -->
<!--     raw vector: -->
*   テキスト以外のリクエストに対しては，バイト型ベクトルとしてボディにアクセスすることができます：

    
    ```r
    content(r, "raw")
    #>   [1] 7b 0a 20 20 22 61 72 67 73 22 3a 20 7b 7d 2c 20 0a 20 20 22 68 65 61
    #>  [24] 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 41 63 63 65 70 74 22 3a 20
    #>  [47] 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 2c 20 74 65 78 74
    #>  [70] 2f 78 6d 6c 2c 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c 2c 20
    #>  [93] 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45 6e 63 6f
    #> [116] 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74 65 22 2c
    #> [139] 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22 68 74 74 70 62 69 6e 2e
    #> [162] 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65 72 2d 41 67 65 6e 74 22
    #> [185] 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 34 33 2e 30 20 72 2d 63 75 72
    #> [208] 6c 2f 30 2e 39 2e 36 20 68 74 74 72 2f 31 2e 31 2e 30 22 0a 20 20 7d
    #> [231] 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22 31 31 39 2e 31 30 34
    #> [254] 2e 34 33 2e 31 32 38 22 2c 20 0a 20 20 22 75 72 6c 22 3a 20 22 68 74
    #> [277] 74 70 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72 67 2f 67 65 74 22 0a 7d
    #> [300] 0a
    ```
    
    <!-- This is exactly the sequence of bytes that the web server sent, so this is -->
    <!-- the highest fidelity way of saving files to disk: -->
    これはまさにwebサーバが送信したバイト列そのものなので，ディスクにファイルを保存する場合には最も正確なやり方です：
    
    
    ```r
    bin <- content(r, "raw")
    writeBin(bin, "myfile.txt")
    ```

<!-- *   httr provides a number of default parsers for common file types: -->
*   httrは，一般的なファイル形式に対するデフォルトのパーサを数多く提供しています：

    
    ```r
    # JSONが自動的に名前付きリストにパースされる
    str(content(r, "parsed"))
    #> List of 4
    #>  $ args   : Named list()
    #>  $ headers:List of 4
    #>   ..$ Accept         : chr "application/json, text/xml, application/xml, */*"
    #>   ..$ Accept-Encoding: chr "gzip, deflate"
    #>   ..$ Host           : chr "httpbin.org"
    #>   ..$ User-Agent     : chr "libcurl/7.43.0 r-curl/0.9.6 httr/1.1.0"
    #>  $ origin : chr "119.104.43.128"
    #>  $ url    : chr "http://httpbin.org/get"
    ```
    
    <!-- See `?content` for a complete list. -->
    パーサの完全な一覧については`?content`を参照してください．
    
    <!-- These are convenient for interactive usage, but if you're writing an API -->
    <!-- wrapper, it's best to parse the text or raw content yourself and check it -->
    <!-- is as you expect. See the API wrappers vignette for more details. -->
    これらのパーサはインタラクティブな用途では便利ですが，APIラッパを書いている場合にはテキストやバイト列のコンテンツを自分でパースして，内容が期待どおりのものか確認するのがベストです．詳細についてはAPIラッパのビネットを参照してください．

<!-- ### The headers -->
### ヘッダ

<!-- Access response headers with `headers()`: -->
レスポンスヘッダには`headers()`でアクセスします：


```r
headers(r)
#> $server
#> [1] "nginx"
#> 
#> $date
#> [1] "Sun, 20 Mar 2016 18:02:50 GMT"
#> 
#> $`content-type`
#> [1] "application/json"
#> 
#> $`content-length`
#> [1] "300"
#> 
#> $connection
#> [1] "keep-alive"
#> 
#> $`access-control-allow-origin`
#> [1] "*"
#> 
#> $`access-control-allow-credentials`
#> [1] "true"
#> 
#> attr(,"class")
#> [1] "insensitive" "list"
```

<!-- This is basically a named list, but because http headers are case insensitive, indexing this object ignores case: -->
これは基本的には名前付きリストですが，HTTPヘッダには大文字と小文字の区別がないので，
このオブジェクトの要素にアクセスする場合も大文字と小文字の違いは無視されます：


```r
headers(r)$date
#> [1] "Sun, 20 Mar 2016 18:02:50 GMT"
headers(r)$DATE
#> [1] "Sun, 20 Mar 2016 18:02:50 GMT"
```

<!-- ### Cookies -->
### クッキー

<!-- You can access cookies in a similar way: -->
クッキーにも同様のやり方でアクセスできます：


```r
r <- GET("http://httpbin.org/cookies/set", query = list(a = 1))
cookies(r)
#>        domain  flag path secure expiration name value
#> 1 httpbin.org FALSE    /  FALSE       <NA>    a     1
```

<!-- Cookies are automatically persisted between requests to the same domain: -->
同じドメインへのリクエストでは，クッキーは自動的に永続化されます：


```r
r <- GET("http://httpbin.org/cookies/set", query = list(b = 1))
cookies(r)
#>        domain  flag path secure expiration name value
#> 1 httpbin.org FALSE    /  FALSE       <NA>    a     1
#> 2 httpbin.org FALSE    /  FALSE       <NA>    b     1
```

<!-- ## The request -->
## リクエスト

<!-- Like the response, the request consists of three pieces: a status line, headers and a body. The status line defines the http method (GET, POST, DELETE, etc) and the url. You can send additional data to the server in the url (with the query string), in the headers (including cookies) and in the body of `POST()`, `PUT()` and `PATCH()` requests. -->
レスポンスと同様，リクエストも3つの部分から成っています．ステータス行，ヘッダ，ボディです．ステータス行はHTTPメソッド（GET，POST，DELETE等）とURLを定義します．（クエリ文字列を使用した）URLや（クッキーを含む）ヘッダ，あるいは`POST()`，`PUT()`，`PATCH()`のボディを利用することで，付加的なデータをサーバに送ることができます．

<!-- ### The url query string -->
### URLクエリ文字列

<!-- A common way of sending simple key-value pairs to the server is the query string: e.g. `http://httpbin.org/get?key=val`. httr allows you to provide these arguments as a named list with the `query` argument. For example, if you wanted to pass `key1=value1` and `key2=value2` to `http://httpbin.org/get` you could do: -->
単純なキーと値のペアをサーバに送る一般的な方法は，クエリ文字列を使うことです．たとえば`http://httpbin.org/get?key=val`といった風にします．httrでは，これらの引数を名前付きリストとして`query`引数で与えることができます．たとえば`key1=value1`と`key2=value2`を`http://httpbin.org/get`に渡したければ以下のようにできるでしょう：


```r
r <- GET("http://httpbin.org/get", 
  query = list(key1 = "value1", key2 = "value2")
)
content(r)$args
#> $key1
#> [1] "value1"
#> 
#> $key2
#> [1] "value2"
```

<!-- Any `NULL` elements are automatically dropped from the list, and both keys and values are escaped automatically. -->

`NULL`要素は自動的にリストから落とされます．またキーと値はどちらも自動的にエスケープされます．


```r
r <- GET("http://httpbin.org/get", 
  query = list(key1 = "value 1", "key 2" = "value2", key2 = NULL))
content(r)$args
#> $`key 2`
#> [1] "value2"
#> 
#> $key1
#> [1] "value 1"
```

<!-- ### Custom headers -->
### カスタムヘッダ

<!-- You can add custom headers to a request with `add_headers()`: -->
`add_headers()`を使ってカスタムヘッダをリクエストに加えることができます：


```r
r <- GET("http://httpbin.org/get", add_headers(Name = "Hadley"))
str(content(r)$headers)
#> List of 6
#>  $ Accept         : chr "application/json, text/xml, application/xml, */*"
#>  $ Accept-Encoding: chr "gzip, deflate"
#>  $ Cookie         : chr "a=1; b=1"
#>  $ Host           : chr "httpbin.org"
#>  $ Name           : chr "Hadley"
#>  $ User-Agent     : chr "libcurl/7.43.0 r-curl/0.9.6 httr/1.1.0"
```

<!-- (Note that `content(r)$header` retrieves the headers that httpbin received. `headers(r)` gives the headers that it sent back in its response.) -->
（`content(r)$header`にはhttpbinが受けとったヘッダが入っていることに注意してください．`headers(r)`はhttpbinが送り返してきたレスポンスのヘッダを与えます．）

<!-- ## Cookies -->
### クッキー
<!-- Cookies are simple key-value pairs like the query string, but they persist across multiple requests in a session (because they're sent back and forth every time). To send your own cookies to the server, use `set_cookies()`: -->
クッキーはクエリ文字列と同様に単純なキーと値のペアですが，セッション中の複数のリクエストに渡って永続化されています（なぜなら毎回のリクエストで送受信がなされるからです）．自分で作ったクッキーをサーバに送るには`set_cookies()`を使用します：


```r
r <- GET("http://httpbin.org/cookies", set_cookies("MeWant" = "cookies"))
content(r)$cookies
#> $MeWant
#> [1] "cookies"
#> 
#> $a
#> [1] "1"
#> 
#> $b
#> [1] "1"
```

<!-- Note that this response includes the `a` and `b` cookies that were added by the server earlier. -->
このレスポンスには以前サーバによって加えられたクッキー`a`と`b`が含まれていることに注意してください．

<!-- ### Request body -->
### リクエストボディ

<!-- When `POST()`ing, you can include data in the `body` of the request. httr allows you to supply this in a number of different ways. The most common way is a named list: -->
`POST()`するときにデータをリクエストのボディに含めることができます．httrでは様々な異なったやり方でデータを与えることができます．最も一般的な方法は名前付きリストを使うことです：


```r
r <- POST("http://httpbin.org/post", body = list(a = 1, b = 2, c = 3))
```

<!-- You can use the `encode` argument to determine how this data is sent to the server: -->
`encode`引数を使って，このデータがどのようにサーバに送られるかを指定できます：


```r
url <- "http://httpbin.org/post"
body <- list(a = 1, b = 2, c = 3)

# Formエンコード
r <- POST(url, body = body, encode = "form")
# Multipartエンコード
r <- POST(url, body = body, encode = "multipart")
# JSONエンコード
r <- POST(url, body = body, encode = "json")
```

<!-- To see exactly what's being sent to the server, use `verbose()`. Unfortunately due to the way that `verbose()` works, knitr can't capture the messages, so you'll need to run these from an interactive console to see what's going on. -->
何がサーバに送られているか正確に知りたければ，`verbose()`を使ってください．残念なことに，`verbose()`の仕様によりknitrがメッセージをキャプチャできないので，何が起こっているのか知りたければ，インタラクティブコンソールでこれらのコードを実行する必要があります．


```r
POST(url, body = body, encode = "multipart", verbose()) # the default
POST(url, body = body, encode = "form", verbose())
POST(url, body = body, encode = "json", verbose())
```

<!-- `PUT()` and `PATCH()` can also have request bodies, and they identically to `POST()`. -->
`PUT()`と`PATCH()`も`POST()`と同じくリクエストボディを持つことができます．

<!-- You can also send files off disk: -->
ディスク上のファイルを送信することもできます：


```r
POST(url, body = upload_file("mypath.txt"))
POST(url, body = list(x = upload_file("mypath.txt")))
```

<!-- (`upload_file()` will guess the mime-type from the extension - using the `type` argument to override/supply yourself.) -->
（`upload_file()`はmime-typeを拡張子から推測しますが，`type`引数によって自分で与えたり上書きすることもできます．）

<!-- These uploads stream the data to the server: the data will be loaded in R in chunks then sent to the remote server. This means that you can upload files that are larger than memory. -->
これらのアップロードにおいては，データはサーバにストリーミングで送信されます．データがRにチャンクとしてロードされ，リモートサーバに送られるのです．したがってメモリに収まらない大きなファイルもアップロードすることができます．

<!-- See `POST()` for more details on the other types of thing that you can send: no body, empty body, and character and raw vectors. -->
他に送信できるもののタイプについて，詳しくは`POST()`を参照してください．ボディなし，空のボディ，文字列型とバイト型のベクトルがあります．

---

この文書は以下のR環境でビルドされました［訳注：訳者の環境です］

```r
sessionInfo()
#> R version 3.2.3 (2015-12-10)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 7 x64 (build 7601) Service Pack 1
#> 
#> locale:
#> [1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
#> [3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
#> [5] LC_TIME=Japanese_Japan.932    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] httr_1.1.0          RevoUtilsMath_3.2.3
#> 
#> loaded via a namespace (and not attached):
#>  [1] R6_2.1.2        magrittr_1.5    formatR_1.2.1   tools_3.2.3    
#>  [5] htmltools_0.3   curl_0.9.6      yaml_2.1.13     stringi_1.0-1  
#>  [9] rmarkdown_0.9.2 knitr_1.12.3    jsonlite_0.9.19 stringr_1.0.0  
#> [13] digest_0.6.9    evaluate_0.8
```

[http-tutorial]:http://code.tutsplus.com/tutorials/http-the-protocol-every-web-developer-must-know-part-1--net-31177