【Go言語】阿部寛さんのHPをechoでホスティングしてみる

## はじめに
今回は、阿部寛さんのHPをGo言語のWebフレームワーク「**echo**」を使用して、ホスティングしてみようと思います。
それでは、echoで表示するまでの過程をご紹介します。

## 環境
- MacBook Air M1

## 使用技術
 - Go言語
     - バージョンは 1.23.2を使用
 - [echo](https://echo.labstack.com/docs/category/guide)
     - 高速で使いやすい、Go言語のWebフレームワーク
     - 今回はechoで簡単なサーバーを作ります
- ベンチマークツール
    - Apache Bench（ab）
    - Bombardier
- VScode
    - エディタはVScodeを使用します


それでは早速プロジェクトに移りましょう。
## プロジェクトの作成
まずは作業ディレクトリを準備します。ここでは、「go-hiroshi」という名前のディレクトリを作成し、その中で作業を進めます。
```terminal:terminal
# 「go-hiroshi」という名前のディレクトリを作成
$ mkdir go-hiroshi

# 作成したディレクトリに移動
$ cd go-hiroshi

# Goのモジュールを初期化
$ go mod init go-hiroshi

# VScodeを起動
$ code .
```

### echoのセットアップ
まずは、server.goファイルを作成し、echoで「Hello World!」を出力させましょう。以下のようにコードを書いてください。
```golang:server.go
package main

import (
	"net/http"
	"github.com/labstack/echo/v4"
)

func main() {
   // Echoのインスタンスを作成
	e := echo.New()

   // "/"エンドポイントにアクセスされたときに"Hello World!"を返すハンドラー 
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!\n")
	})
	e.Logger.Fatal(e.Start(":1323"))
}
```
echoはミドルウェアのサポートをデフォルトで提供しています。
例えば、以下のようなミドルウェアを簡単に組み込むことができます。
```go:
e.Use(middleware.Logger()) // ログを記録するミドルウェア
e.Use(middleware.Recover()) // パニック発生時にサーバーを復旧させるミドルウェア
```
ですが、今回は簡単なサーバー構築ができればいいので使用しません。

コードを書き終えたら必要な依存関係をインストールし、Goを起動させましょう。
```terminal:terminal
# 依存関係をインストール
$ go mod tidy

# サーバーを実行
$ go run server.go
```
:::note 
`go mod tidy`はGoモジュールの依存関係を整えるためのコマンドです。
依存関係を追加した後や削除した後には、適宜このコマンドを実行しましょう！
:::

起動できたら、ブラウザで`http://localhost:1323`と打ち、『Hello World!』が返ってくればOKです！
これで一旦、echoのセットアップは終わりです。
次に、阿部寛さんのHPのindex.htmlなどをwgetで持ってくる操作などを行います。

### Makefileの作成
作業ディレクトリ下に`Makefile`[^1]を作成しましょう。
```
$ touch Makefile
```

以下のように書いてください。
```makefile:Makefile
.PHONY: clone-hiroshi bench bombardier

clone-hiroshi:
	wget \
		-P public \
		--recursive \
		--no-parent \
		http://abehiroshi.la.coocan.jp/

bench:
	ab -n 1000 -c 10 http://localhost:8080/

bombardier:
	bombardier -c 10 -n 1000 http://localhost:8080/			
```
- **.PHONY:**
Makefileで定義されたターゲット名が実在するファイルやディレクトリと競合しないようにするための指定です。ここでは、clone-hiroshi、bench、bombardierが該当します。

1\. **clone-hiroshi**
阿部寛さんのホームページをローカル環境に保存します。wgetを使用して、指定したURL(http://abehiroshi.la.coocan.jp/) のコンテンツを再帰的にダウンロードし、`-P`オプションをつけ**public**ディレクトリに保存するよう指定しましょう。

2\. **bench**
Apache Benchを使用して、ローカルホスト(http://localhost:8080/) に対する負荷テストを実行します。

- リクエスト数: 1000件
- 同時接続数: 10件

3\. **bombardier**
bombardierツールを使用して、同じくローカルホストに対する負荷テストを行います。こちらもリクエスト数1000件、同時接続数10件でテストします。

ここから作業を進めていく上で以下のコマンドを準備しておく必要があります。

:::note
- `make`コマンド
    - `make --version`でバージョンが表示されるか確かめてください
    - Macユーザーの方は`brew install make`でインストールが可能
- `wget`
    - `wget --version`でバージョンが表示されるか確かめてください
    - Macユーザーの方は`brew install wget`でインストールが可能
:::

それではVScode上のターミナルを開いて、以下のコマンドを実行してください。
```terminal
$ make clone-hiroshi
```
作業ディレクトリ下に`public`ディレクトリが作成されたらOKです！

次は、`server.go`ファイルの修正を行います。
現在、ルートディレクトリに対して「Hello World!」が返されるようになっていると思うのですが、こちらをStaticファイルを返すようにしてあげます。
```golang:server.go
package main

import (
	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()

	// 静的ファイルの提供
	e.Static("/", "public")

	// ルートハンドラの設定
	e.File("/", "public/index.html")

	e.Logger.Fatal(e.Start(":8080"))
}
```

ただ、このままだとおそらくGoを起動させても`404 Not Found`が返ってくると思います。
そこで、`public`ディレクトリ内のファイルに修正をしなければならないので以下の手順に従って作業を進めてください。
まずは、`public`ディレクトリに移動し、`abehiroshi.la.coocan.jp`配下のファイルを全て移動させます。
```terminal:terminal
$ cd public/

$ mv abehiroshi.la.coocan.jp/* ./

# abehiroshi.la.coocan.jpディレクトリは削除します
$ rm -rf abehiroshi.la.coocan.jp
```

阿部寛さんのHPはSJISで保存されているので、これを文字コードがUTF-8になるように変換していきます。
```terminal:terminal
# publicディレクトリ内の".htm"拡張子を、全てUTF-8に変換する
$ find . -name "*.htm*" | xargs nkf --overwrite -w
```
:::note
- `xargs`コマンド
    - 標準入力から読み取った入力をコマンドライン引数として別のコマンドに渡すことができる
    - Macユーザーの方は`brew install findutils`でインストール可能

- `nkf`(Network Kanji Filter)コマンド
    - 文字コードの変換を行うコマンドラインツール
    - SJISからUTF-8に変換するために使用
    - Macユーザーの方は`brew install nkf`でインストール可能
:::

それでは、Goを起動させ阿部寛さんのHPが表示されるか確認しましょう。
```terminal:terminal
$ go run server.go
   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.12.0
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080
```
以下の画像のように、`localhost:8080`で起動できたら成功です！
![スクリーンショット 2024-11-16 23.23.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763692/1c69cb30-6506-3cb0-9e17-2662049037ac.png)

うまくいかない場合は、キャッシュが残っている可能性があります。Chromeを使用している方は以下の手順でキャッシュをクリアし、ホットリロードを有効にしてください：
1\. **Chromeで「検証」を開く**
- Macの場合
    - `cmd+option+i`を押して開きます
- Windowsの場合
    - `ctrl+shift+i`を押して開きます

2\. **`Network`タブを開く**
- 「検証」ツールの上部にあるタブから`Network`を選択します

3\. **Hard reload pageを選択**
-  `cmd+shift+P`（Mac）または`ctrl+shift+P`（Windows）を押してコマンドパレットを開きます
-  以下の画像の通りにしていただくとホットリロードができると思います。

![スクリーンショット 2024-11-16 23.28.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763692/25b5d349-09f8-8441-0d1c-8f3b47af8e7f.png)

## さいごに
本記事では、Go言語＋Echoで阿部寛さんのHPをホスティングする方法をご紹介しました。
Go言語でのウェブサーバー構築や、ベンチマークツールを用いたパフォーマンス測定の手法について学ぶ良い機会になったと思います。

このプロジェクトを通じて、基本的なサーバーの作成から、静的ファイルの提供、ベンチマークテストまでの一連の流れを理解することができました。今後は、さらに高度なミドルウェアの使用や、他のベンチマークツールの活用も試してみたいと思います。



[^1]:Makefile：ソフトウェアのビルドプロセスを自動化するための設定ファイル