[初心者向け]Webサービスを利用する際のHTTPについて再入門

[初心者向け]Webサービスを利用する際のHTTPについて再入門

おはようございます、もきゅりんです。

前回の続きです。

対象は、何となくAWSを触っているような、駆け出しITエンジニアさんです。IT業界で長く生息する方々には一般常識レベルのことが多いかと思います。

前回はDNSからTCPコネクションまでを辿ってきました。TCPコネクションが確立されたので、次はアプリケーション層であるHTTPプロトコルでのやり取りとなります。

http

ところで、なぜTCPが確立されるとアプリケーション層でやり取りできるのでしょうか。

ソケット

アプリケーションがTCPやUDPを利用するときに、OSが用意しているIPアドレスとポート番号の組み合わせから構成される、ソケットと呼ばれるAPIを使って通信を行うことができます。

このソケットのおかげで、アプリケーションは特にネットワークを意識することなく、プログラムに必要な実装ができます。

HTTPを掘り下げていこうとすると、HTTPそれだけでなく、RESTの概念 *1の把握が付随してくるとは思うのですが、今回の主旨はHTTPそのものではなく、クライアントがドメインネームからWebサービスを利用するまで、を少し掘り下げる、のため割愛します。

HTTPとURIとHTMLのセット

HTTPを利用するために、セットとなるのがURIとHTMLです。

まず、URI(Uniform Resource Identifier)とは、その名の通り、「統一化されたリソースID」です。Web上にあるすべてのリソースを一意的に示すことができます。

HTML(Hypertext Markup Language)は、タグで文書構造を表現するマークアップ言語の1つです。インターネットを通じて不特定多数の情報とリンクができるハイパーリンク、画像等のマルチメディアを埋め込むハイパーテキストとしての機能を含め、さまざまな機能をもっています。

HTTP(Hypertext Transfer Protocol)は、URIによって対象を指定し、対象上で実行したいリクエストをします。そのリクエストに対する、 HTMLなどのマークアップ言語によって記述された結果(レスポンス)を転送します。

関係性は下図です。

http_relation

『出典:山本(2015) p.005』

8つのHTTPメソッド

HTTPが指定とした対象にリクエストするのは、8つのメソッドです *2。実際のHTTP通信ではGETとPOSTメソッドだけで殆どを占めます。

タイプ 内容
GET 指定されたURIのリソースを取り出します
POST クライアントがサーバにデータを送信します
PUT クライアントが指定したURIにリソースを保存します/ URIが指し示すリソースが存在しない場合は、サーバはそのURIにリソースを作成します
DELETE 指定したURIのリソースを削除します
HEAD サーバはHTTPヘッダのみ返します
OPTIONS サーバがサポートしている情報を調査します
TRACE サーバまでのネットワーク経路をチェックします
CONNECT TCPトンネルを接続します

HTTPメッセージと構成

HTTPは、クライアントが出したリクエストをサーバが処理してレスポンスを返すプロトコルです。 このようなプロトコルをリクエスト/レスポンス型のプロトコルと呼びます。また、リクエストを出したクライアントはレスポンスが返ってくるまで待機します。

HTTPのリクエストとレスポンスをまとめて「HTTPメッセージ」と呼びます。 それぞれ以下のような構成となっています。

  • リクエストメッセージ
    • リクエストライン
    • ヘッダ
    • ボディ
  • レスポンスメッセージ
    • ステータスライン
    • ヘッダ
    • ボディ

使ってみる

実際にHTTPメソッドをテストしてみるのに便利なサイトがあったので、curlコマンドとこちらを利用してみます。

curl / Docs / Tool Documentation / Manual

http://httpbin.org

まずはサーバがサポートする情報を確認してみます。

# OPTIONS
$ curl -vXOPTIONS http://httpbin.org
* Rebuilt URL to: http://httpbin.org/
*   Trying 3.225.168.125...
* TCP_NODELAY set
* Connected to httpbin.org (3.225.168.125) port 80 (#0)
> OPTIONS / HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
< Access-Control-Allow-Origin: *
< Access-Control-Max-Age: 3600
< Allow: GET, OPTIONS, HEAD
< Content-Type: text/html; charset=utf-8
< Date: Fri, 18 Oct 2019 04:39:27 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 0
< Connection: keep-alive
<
* Connection #0 to host httpbin.org left intact

オプション-vを付与することで、リクエストヘッダも記載されています。対象ドメインのport80にTCPコネクション確立されている様子が伺えます。

GET, POST, PUT, DELETE, PATCH, OPTIONSに対応しているというのが分かりました。

続けて、GET, POST, DELETEと実行してみます。

# GET
$ curl -v http://httpbin.org
* Rebuilt URL to: http://httpbin.org/
*   Trying 52.200.159.44...
* TCP_NODELAY set
* Connected to httpbin.org (52.200.159.44) port 80 (#0)
> GET / HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: text/html; charset=utf-8
< Date: Fri, 18 Oct 2019 04:57:07 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 9593
< Connection: keep-alive
<
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>httpbin.org</title>
    <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700"
        rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="/flasgger_static/swagger-ui.css">
    <link rel="icon" type="image/png" href="/static/favicon.ico" sizes="64x64 32x32 16x16" />
...

トップページHTMLが返却されているのが分かります。

次はパラメータを付けてリクエストしていきます。

$ curl -v http://httpbin.org/get?user=1
*   Trying 52.200.159.44...
* TCP_NODELAY set
* Connected to httpbin.org (52.200.159.44) port 80 (#0)
> GET /get?user=1 HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Fri, 18 Oct 2019 04:48:59 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 230
< Connection: keep-alive
<
{
  "args": {
    "user": "1"
  },
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.54.0"
  },
  "origin": "xx.xxx.xxx.xxx, xx.xxx.xxx.xxx",
  "url": "https://httpbin.org/get?user=1"
}
* Connection #0 to host httpbin.org left intact
# POST
$ curl -v -d "name=Rafael%20Sagula&phone=3320780" http://httpbin.org/post
*   Trying 52.200.159.44...
* TCP_NODELAY set
* Connected to httpbin.org (52.200.159.44) port 80 (#0)
> POST /post HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 34
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 34 out of 34 bytes
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Fri, 18 Oct 2019 04:52:38 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 411
< Connection: keep-alive
<
{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "name": "Rafael Sagula",
    "phone": "3320780"
  },
  "headers": {
    "Accept": "*/*",
    "Content-Length": "34",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.54.0"
  },
  "json": null,
  "origin": "xx.xxx.xxx.xxx, xx.xxx.xxx.xxx",
  "url": "https://httpbin.org/post"
}
* Connection #0 to host httpbin.org left intact
# DELETE
$ curl -vXDELETE http://httpbin.org/delete?user=3
*   Trying 3.225.168.125...
* TCP_NODELAY set
* Connected to httpbin.org (3.225.168.125) port 80 (#0)
> DELETE /delete?user=3 HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Fri, 18 Oct 2019 04:54:55 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 296
< Connection: keep-alive
<
{
  "args": {
    "user": "3"
  },
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.54.0"
  },
  "json": null,
  "origin": "xx.xxx.xxx.xxx, xx.xxx.xxx.xxx",
  "url": "https://httpbin.org/delete?user=3"
}
* Connection #0 to host httpbin.org left intact

それぞれリクエストヘッダにHTTPリクエストメソッドおよびパラメータが記載されて送信されているのが確認できます。このAPIでは、jsonでリクエストの内容などがレスポンスされます。

その他

最近では、WEBとAPPとでサーバを分離することも多く、避けて通れないのがCORS *3だと思います。CORSに関しては下記弊社ブログも参考になります。

CORS(Cross-Origin Resource Sharing)について整理してみた

まとめ

これで、ドメインネームから目的のサービスのIPアドレスに辿り着き、HTTPプロトコルを用いてWebサイトを閲覧するリクエスト、データ送信するリクエストなど行うことを確認してきました。

次はこのリクエストに応じて、サーバがデータベースからどのようにデータ取得するか、データを保存するか、を確認していきたいと思います。

[初心者向け]Webサービスを利用する際のDB接続とデータ保存について再入門へ続きます。

参考:

脚注

  1. ステートレスなクライアント/サーバプロトコル,統一されたインターフェイス,リソースを一意に識別する「汎用的な構文」,アプリケーションの情報と状態遷移の両方を扱うことができる「ハイパーメディアの使用」 など
  2. HTTPの仕様以外で定義しているメソッドは、IANAのHypertext Transfer Protocol (HTTP) Method Registry[10]で管理されている。WebDavで使用するものや、 RFC 5789 のPATCHメソッドなどがあります。
  3. Cross-Origin Resource Sharing
    最初にリソースが提供されたドメインではない、別ドメインからリソースをリクエストできるようにする仕組み。