はじめに
以前にhttplib.hを使ったHTTPサーバ/クライアントを作成した。
※以前の記事:C++ HTTPサーバー/クライアントを作る
今回はhttplib.hを使ってブラウザ表示できるwebサーバを作ってみた。
httplib.hのダウンロード/コピー
以下のgithubからダウンロードしてくる。
https://github.com/yhirose/cpp-httplib
もしくは、Googleがyhiroseさんの実装を取り込んだGoogle gitからダウンロードする。
chromium.googlesource.com/httplib.h
※補足 (2023/8/25追記)
g++のバージョンによっては起動すると、terminate called after throwing an instance of 'std::regex_error'
となり、regexでエラーとなってしまうようです。
@hiroaki_yamadaさんから教えていただきました。
regexはC++ 11から追加された機能になるため、バージョン4.9以上にすれば、動作すると思います。
以下は参考ページになります。
今回の動作環境は9.4.0でした。
ディレクトリ構成
httplib.h と同じ階層にserverSample.cppを置く。
htmlディレクトリはブラウザで表示させるファイル置き場。
├── CMakeLists.txt
├── html
│ ├── index.html
│ └── page1
│ └── page.html
├── httplib.h
└── serverSample.cpp
実装
Readme.mdのServer Exampleを参考にwebサーバアプリを作成する。
実装は以下になる。(ここをクリック)
#include "httplib.h"
#include <iostream>
class FileReader {
public:
int Read(std::string file_path) {
std::ifstream ifs(file_path);
std::string str = "";
record_data = "";
if (ifs.fail()) {
std::cerr << "Failed to open file." << std::endl;
return -1;
}
while (getline(ifs, str)) {
record_data += str;
}
return 0;
}
std::string GetRecord() { return record_data; }
private:
std::string record_data;
};
int main(void)
{
using namespace httplib;
Server svr;
FileReader reader;
std::cout << "start Server" << std::endl;
std::string file_path = "../html";
svr.Get("/", [&](const Request& req, Response& res) {
reader.Read(file_path + "/index.html");
std::string html = reader.GetRecord();
res.set_content(html, "text/html");
});
svr.Get(R"(/(.+))", [&](const Request& req, Response& res) {
reader.Read(file_path + req.target);
std::string html = reader.GetRecord();
res.set_content(html, "text/html");
});
svr.listen("127.0.0.1", 8080);
}
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# set the project name and version
project(httpSample CXX)
# find package
find_package(Threads REQUIRED)
# compile executable file
add_executable(serverSample serverSample.cpp)
# module, library, target link
target_link_libraries(serverSample PUBLIC "-pthread")
実装解説
- class FileReader
- htmlファイルを読み込むためのクラス
-
int main(void)
関数のstd::string file_path = "../html";
- html置き場のディレクトリパスを指定する。
- 以下のコマンドでbuildディレクトリに実行ファイルを生成する。
cmake -Bbuild -H. cmake --build build
- buildディレクトリからアプリを実行したため
"../html"
を指定している。
-
res.set_content(html, "text/html");
- text/htmlを指定する。
- ※ここの値は状況に応じてcssやjavascriptに変える必要がある。
-
svr.Get("/", [&](const Request& req, Response& res) {
- Get methodで/を要求された時はhtml/index.htmlをブラウザに表示させる。
-
svr.Get(R"(/(.+))", [&](const Request& req, Response& res) {
- R"(/(.+))"は正規表現。
- /以降のパスを要求された時はhtml配下のhtmlファイルをブラウザに表示させる。
※補足 (2023/8/25追記)
@yhiroseさんから教えていただきました。 > まさかの作者さんからでした。
今回のhtmlのディレクトリにアクセスさせるため、
std::string file_path = "../html";
をsvr.Get(R"(/(.+))"
内の
reader.Read(file_path + req.target);
に設定していました。
頂いたコメントによると、以下のcpp-httplibのStatic File Server機能を使用できるようです。
svr.set_mount_point("/", "../html")
これについて、再度実装してみました。
物凄く実装が綺麗になりました。
#include "httplib.h"
#include <iostream>
int main(void)
{
using namespace httplib;
Server svr;
std::cout << "start Server" << std::endl;
svr.set_mount_point("/", "../html");
svr.listen("127.0.0.1", 8080);
}
これだけでWebサーバを作成できました。
簡単で驚きました。
Googleがアップしていたのが、2017年の更新。
この時はまだStatic File Server機能は追加されてませんでした。
※ご本人様のGithubを確認せずに、こちらを使ってました。。
ご本人様のGithubを確認したら、2023年の更新。
set_mount_pointすごぃ。。。
改めて記事にしてまとめます。
余談
PCスペックによってはレスポンスが遅く、htmlにリンクしたjavascriptがブラウザに表示できないことがある。
さいごに
以上で終了です。
メモ程度ですが、ご参考になれば幸いです。