初心者によるHTTP基礎概念勉強ノート＆Node.jsで簡単なサーバを作ってみた

## HTTP基礎概念
### なぜネットの世界にはプロトコル(Protocol)が必要ですか？
- 規模化をする前提に、内容の統一や標準化が必要。（standardization）

### 標準化した内容 Header & body
- Header
URL、メソッド（Method）、ステータスコード(Status Code)などの情報を伝える。
- body（HTMLのタグではない）
Response Bodyの内容、ソースコード。

### よく見られる状態コード一覧
- **200 OK**　リクエスト成功
- **204 No Content**　リクエスト受理しましたが、返すレスポンスはない。
    →　DELETEメソッドであるリソースを削除したが、返す内容がない。
- **301 Moved Permanently**　リソースが恒久的に移動した。
    →　GETメソッドで最初のヘッダから移動先のLocationを取得したら、そのあと同じウェブサイトにアクセスしても新しい移動先に移転される。
- **302 Found**　リソースが一時的に移動された（**Moved Temporarily）**
    →　301と同じくGETメソッドでヘッダからLocationが表示されるが、その後アクセスしても自動的に移転されない。この特性を利用されるようになって、**302**は**Found**（リソースが移動したの発見！）、**303**は**ほかのリソースを参照せよ**、**307**は**一時的にリダイレクト。**
- **400 Bad Request**　クライアントのリクエストがおかしい。定義されてないメソッド使ったかもしれません。
- **404 Not Found**　ページが見つからなかった。
- **500 Internal Server Erro**r　サーバ側内部にエラーが発生した。
- **503 Service Unavailable**　過負荷かメンテナンスでサービスが一時利用不可。

### TCP 3ウェイ・ハンドシェイク（TCP three-way handshaking）
ClinetとSeverが各自に送信と受信機能を持った人間のように会話したら、
C: ヤッホー、いる？　（メッセージ受け取ったSever受信機能：OK） SYN
S: いるよ、こんにちは！　（メッセージ受け取ったClinet受信と発信機能：OK） SYN+ACK
C: よかったー、こんにちは！　（メッセージ受け取ったSever発信機能：OK） ACK

相手の反応から自分の機能を検証していくような仕組みです。
TCP（Transmission Control Protocol）はこのような処理を経て、低速だけど確実に相手と接続して通信を行うため、信頼性（reliability）が必要な上位プロトコル（HTTP/FTP/POPなど）に最適化処理を提供する。
→ ウェブサイトの閲覧、ファイルの転送、メールの送受信など
UDP（User Datagram Protocol）はTCPと違い、高速転送のために途中で少しパケットをなくしても許すという信頼性のないものの通信を行う。
→ 音声通話、動画など

### 知っておくべき TCP/TP ポート（Port）
- HTTP 80
- HTTPS 443
- FTP 21
例：13.114.40.48 **:443** (https://github.com/)

### HTTP リクエストメソッド（HTTP Request Method）
Clinet　--Request-→ Sever
Clinet　←-Request-- Sever

- GET　リソースの取得
- POST　リソースの送信
- DELETE　リソースの削除
- PUT　リソースの作成または更新
- PATCH リソース一部変更
- HEAD　GETと同じリソースを取得するが本文（Response Body）なし

#### GET
一番よく使われるメソッドです。リスポンスされた内容がブラウザエンジンで解析した後画面にレンダリング。

#### POST
例えば、ログインするときIDやパスワード入力しDevToolsでsesseion（Severとの会話）、
NetworkのPayload（実際送信したメッセージ）チェックしてみたら、
![Screenshot7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2477698/9eade3d7-5cfa-72f1-6584-19982e9a7867.png)
Form DataではPOSTメソッドで送信したリソースを表示する。
view sourceを押したら、POST Requestを使ったとき実際に送信したコード（エンコード状態）を示す。

#### PUT vs. PATCH（ドキュメントによって違うときもある。）
PUT：リソース全体を置き換える
PATCH：リソース部分的に変更、または追加する。

### Header & bodyをゲットしてみる
（以下はGoogleを例にした）
##### 方法一　DevTools → Network
![Screenshot6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2477698/7e4c08c8-b187-ee51-0a0e-dc596ec75374.png)
Headersからメソッドやステータスコードなどが見られる。
また、横にあるResponseは、Response Bodyというページのソースコードです。

##### 方法二　npm request
Request - Simplified HTTP client
https://www.npmjs.com/package/request
CLIターミナルで扱われるnpmツールの一つです。
すでに二年以上アップデートすることもなく、今はdeprecated（未推奨）になっていますが、まだよく使われるツールとして週間ダウンロード数が凄いです。

```
$ npm i request
```
終わったら、VScodeを開いて
```
// 不要な注釈を削除した
const request = require('request');
request('http://www.google.com', function (error, response, body) {
  console.error('error:', error);
  console.log('statusCode:', response && response.statusCode);
  // console.log('body:', body);
});
```
Response Bodyを出力するとターミナルではリソースコードが長くなって読みにくいと、statusCodeをチェックするだけならここを注釈しておいたほうがいいと思います。
ターミナルに実行させたら、
```
error: null
statusCode: 200
```
エラーなし、さらに成功というステータスコードを返しました。
次はリソースコードをゲットしたいので、
```
const request = require('request');
request('http://www.google.com', function (error, response, body) {
  // console.error('error:', error);
  // console.log('statusCode:', response && response.statusCode);
  console.log('body:', body);
});
```
ファイルとして保存します。
```
$ node request.js > google.html
```
（注1：文章を書きながら検証したら「stdout is not a tty」が出てきました。どうやら、この">(redirect)"で出力しようとすると問題を起こしたようで、一回"bash"を入れたらうまく行きました。）
（注2：この方法で保存したファイルは、右クリックしてダウンロードしたページとどこか違っているかまだ分からないです。）

自分はまだターミナルの使い方は慣れてないのでよくDevToolsに頼っています。ターミナルの練習もかねてこの二つの方法やってみました。


## Node.jsでサーバ作り実践してみた
### 環境＆ツール
- OS: Windows 10
- Git-bash 2.35.1.windows.2
- nvm 1.1.9
- Node.js v14.16.0
- VScode


### 簡単かつシンプルなサーバ実践編
```
// Require http module from Node.js
const http = require('http')

// Define server related variables
const hostname = 'localhost'
const port = 5000

// Handle request(req) and response(res)
const server = http.createServer(function (req, res) {
  if (req.url === '/') {
    // ステータスコードの設立
    res.statuCode = 200;
    // text/plain：HTML要素が使えないテキスト
    res.setHeader('Content-Type', 'text/plain');
    res.write(`<h1>Welcome!</h1>`);
    res.end('This is my root page.');

  } else if (req.url === '/hello') {
    // writeHeadでステータスコードとContent-Typeを設定
    // text/html：HTML要素が使えるテキスト
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write(`<h1>Hello world!</h1>`);
    res.end('This is hello world page.');

  } else if (req.url === '/redirect') {
    // 新しい移動先に転送
    res.writeHead(302, { 'Location': '/' });
    res.end();

  } else {
    // 適当にアクセスされたルータは全部404で返す
    res.writeHead(404);
    res.end('Invalid Request!');

  }
})


// Start and listen the server
server.listen(port, hostname, () => {
  console.log(`The Node.js web server is listening on http://${hostname}:${port}`)
})

```
## 参考資料
Request - Simplified HTTP client
https://www.npmjs.com/package/request

HTTP リクエストメソッド
https://developer.mozilla.org/ja/docs/Web/HTTP/Methods

HTTP | Node.js v17.7.1 Documentation
https://nodejs.org/api/http.html


## 感想
フロントエンドの世界を知るためにネットワークの基礎概念を勉強して今回もアウトプットしてみました。
HTTP基本の仕組みや状態コードの識別、サイト作りが現状としてブラウザエンジンと分離していること等々が、分かりました。
今回Node.jsで実践する前、すでにExpressフレームワークとExpress-handlebarsパッケージ触って作ったことがあり、ツールの存在のおかげでサイト作りが大変便利になってますね。。
Node.jsドキュメント読んだら書き方も構造の話もまだ理解していないので、学問だと思って未来の自分に課題を残します！