🗽

HTTP通信について深掘りしてみた

2023/09/16に公開

HTTPとは

HTTPとは、HyperText Transfer Protocolの略で、WebブラウザとWebサーバー間でHTMLなどのデータをやり取りするための通信プロトコルです。

クライアントでおこなわれること

  1. リクエストメッセージの構築
  2. リクエストメッセージの送信
  3. レスポンスが返るまで待機
  4. レスポンスメッセージの受信
  5. レスポンスメッセージの解析
  6. クライアントの目的を達成するために必要な処理

サーバーでおこなわれること

  1. リクエストの待機
  2. リクエストメッセージの受信
  3. リクエストメッセージの解析
  4. 適切なアプリケーションプログラムへの処理の委譲
  5. アプリケーションプログラムから結果を取得
  6. レスポンスメッセージの構築
  7. レスポンスメッセージの送信

headers

HTTPのリクエストやレスポンスには、HTTPのバージョンや、通信相手の情報、通信の状態などを示す情報が含まれています。これらの情報をヘッダーと呼びます。
メタデータとも呼ばれます。
メタデータとは、データに関するデータのことです。例えば、写真のデータには、撮影日時や、撮影場所などの情報が含まれています。このようなデータをメタデータと呼びます。

body

HTTPのリクエストやレスポンスには、ヘッダーの他に、本文となるデータを含めることができます。これらのデータをボディと呼びます。
リソースを新しく作成する場合は、ボディにリソースの内容を含めて送信します。また、リソースを更新する場合は、ボディに更新後のリソースの内容を含めて送信します。

チャンク

HTTP/1.1では、ボディのデータを複数の塊に分割して送信することができます。これをチャンクと呼びます。
チャンクは塊、小さな塊と表現されることもある。
チャンクを使うことで、サーバーはボディのデータを全て受信してからレスポンスを返すのではなく、チャンクごとにレスポンスを返すことができます。

8つしかないHTTPメソッド

HTTPメソッドとは、HTTPリクエストの種類を表すものです。HTTPメソッドには、GET、POST、PUT、DELETE、HEAD、OPTIONS、TRACE、CONNECTの8種類があります。

https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/CONNECT

メソッド 説明
GET リソースの取得
POST リソースの新規作成
PUT リソースの更新
DELETE リソースの削除
HEAD リソースのヘッダーの取得
OPTIONS リソースがサポートしているメソッドの取得
TRACE 自分宛にリクエストメッセージを返す(ループバック)試験
CONNECT プロキシ動作のトンネル接続への変更

HTTPのステータスコードの種類

HTTPのレスポンスには、ステータスコードと呼ばれる3桁の数字が含まれています。ステータスコードは、リクエストの処理結果を表すものです。

https://developer.mozilla.org/ja/docs/Web/HTTP/Status/100

ステータスコード 説明
100 処理中
200 成功
300 リダイレクト
400 クライアントエラー
500 サーバーエラー

100の時は、処理中という意味です。例えば、リクエストのボディが大きい場合に、サーバーはリクエストのボディを受信するのに時間がかかることがあります。その場合、サーバーは100を返して、リクエストのボディを受信していますよということをクライアントに伝えます。

200の時は、成功という意味です。例えば、リクエストが成功した場合に、サーバーは200を返して、リクエストが成功したことをクライアントに伝えます。

300の時は、リダイレクトという意味です。例えば、リクエストしたリソースが移動した場合に、サーバーは300を返して、リソースが移動したことをクライアントに伝えます。
PHPで使った例だとPOSTした後に違うページへ飛ばすときに使う。

404で例に出すと、Not Foundという意味です。例えば、リクエストしたリソースが存在しない場合に、サーバーは404を返して、リソースが存在しないことをクライアントに伝えます。
あるページにアクセスしたときに、そのページが存在しない場合に表示されるページ。

500の時は、サーバーエラーという意味です。例えば、サーバー内部でエラーが発生した場合に、サーバーは500を返して、エラーが発生したことをクライアントに伝えます。
サーバーが起動していない場合に表示される。

コードにするとこんな感じになります。

HTTP POSTメソッドを使った例です。これは、ローカル環境に構築したモックサーバーにデータを送信するロジックです。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
  </head>
  <body>
    <!-- http://localhost:3000/postsこのURLのモックにHTTP POSTする -->
    <div class="card">
      <form action="http://localhost:3000/posts" method="POST">
        <input class="title" type="text" name="title" />
        <input class="content" type="text" name="content" />
        <input type="submit" value="送信" />
      </form>
    </div>
    <script>
      /// [送信ボタンを押したら、POSTする]
      /*
      e.preventDefault();は、デフォルトのイベントをキャンセルするメソッド.
      これを書かないと、送信ボタンを押したら、ページがリロードされてしまう.
      */
      document.querySelector("form").addEventListener("submit", (e) => {
        e.preventDefault();
        const title = document.querySelector("input[name=title]").value;
        const content = document.querySelector("input[name=content]").value;
        const data = { title, content };
        console.log(data);
        fetch("http://localhost:3000/posts", {
          method: "POST",// HTTPメソッドを指定
          mode: "cors",// クロスオリジンリクエストを許可することで、サーバーとの通信を可能にする
          headers: {
            "Content-Type": "application/json",// リクエストヘッダーにJSON形式のデータを含める
          },
          body: JSON.stringify(data),// リクエストボディにJSON形式のデータを含める
        });
      });
    </script>
  </body>
</html>

見た目も整えたいのでCSSを使います。

body {
  background-color: #f5f5f5;
  font-family: "Roboto", sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  color: #212529;
  text-align: left;
  margin: 0;
  padding: 0;
}

.card {
  /*.cardを画面中央寄せにしたい*/
  position: absolute;
  top: 50%;
  left: 50%;
  /*transformを使って、.cardを中央寄せにする*/
  transform: translate(-50%, -50%);
  background-color: #fff;
  width: 300px;
  height: 150px;
}

form {
  margin-top: 20px;
  /*画面中央寄せにする*/
  display: flex;
  justify-content: center;
  align-items: center;
  /*縦並びにする*/
  flex-direction: column;
  /*画面の高さいっぱいにする*/
}

.title {
  margin-bottom: 10px;
}

.content {
  margin-bottom: 10px;
}

こちらの本にモックサーバーの使い方をご紹介しております。
https://zenn.dev/joo_hashi/books/b78da6bf581547

Flutterのdioというパッケージを使用した例もご紹介しておきます。httpというパッケージもあるのですが、Flutter Webで使うとなぜかエラーが出てくる?
dioは大丈夫でしたね🤔

試してみたい人はこちらのパッケージを追加して使ってみてください。
https://pub.dev/packages/dio
https://pub.dev/packages/logger

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Steamy Mug Animation',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HttpExample(),
    );
  }
}

class HttpExample extends StatefulWidget {
  const HttpExample({Key? key}) : super(key: key);

  
  State<HttpExample> createState() => _HttpExampleState();
}

class _HttpExampleState extends State<HttpExample> {
  final _title = TextEditingController();
  final _content = TextEditingController();

  final _logger = Logger();
  final _dio = Dio(
    BaseOptions(
      baseUrl: 'http://localhost:3000',
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
    ),
  );
  /*
  http://localhost:3000/postsにPOSTリクエストを送る
  送るデータは、titleとcontent
  */

  Future<void> postBook() async {
    try {
      final response = await _dio.post(
        '/posts',
        // dataとは、送るデータのこと
        data: {
          'title': _title.text,
          'content': _content.text,
        },
        /*
        optionsとは、ヘッダーのこと
        Content-Typeとは、送るデータの形式のこと
        今回は、json形式で送るので、application/jsonとなる
        */
        options: Options(
          headers: {
            'Content-Type': 'application/json',
          },
        ),
      );
      _logger.i(response);
    } catch (e) {
      throw Exception(e);
    } finally {
      _logger.i('finally');
    }
  }

  
  void dispose() {
    _title.dispose();
    _content.dispose();
    super.dispose();
    _logger.i('disposeが呼ばれました');
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Http Example'),
      ),
      body: Center(
        child: Column(
          children: [
            const SizedBox(height: 20),
            SizedBox(
              width: 200,
              height: 50,
              child: TextField(
                controller: _title,
                decoration: const InputDecoration(
                  hintText: 'title',
                  border: OutlineInputBorder(),
                ),
              ),
            ),
            const SizedBox(height: 20),
            SizedBox(
              width: 200,
              height: 50,
              child: TextField(
                controller: _content,
                decoration: const InputDecoration(
                  hintText: 'content',
                  border: OutlineInputBorder(),
                ),
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                postBook();
              },
              child: const Text('post'),
            ),
          ],
        ),
      ),
    );
  }
}

最後に

本を読んで知識を深掘りしようとすると、永遠に終わらなくて今知っていればいいかなと思う情報だけまとめました。Webの勉強を勉強していた時になんとなく、ajax使ってたのですが知識の深掘りがないと、bodyとかheaderの意味がわからないので、コードに何が書かれているのか理解できなかったですね。
理解を深めて、APIの設計もやってみたいですね。

古い本ですがこちらの書籍が学習の参考になりました。
https://www.amazon.co.jp/Webを支える技術-HTTP、URI、HTML、そしてREST-WEB-PRESS-plus/dp/4774142042/ref=sr_1_1?adgrpid=102912038115&hvadid=651192011668&hvdev=c&hvlocphy=9053283&hvnetw=g&hvqmt=e&hvrand=3270319539838048868&hvtargid=kwd-394859824714&hydadcr=21894_13456357&jp-ad-ap=0&keywords=web+を支える技術&qid=1694834108&sr=8-1

Jboy王国メディア

Discussion