C++ Http/Https服务器和客户端库cpp-httplib

丁丁爸爸的技术 2020-04-26

A C++ header-only HTTP/HTTPS server and client library
https://github.com/yhirose/cpp-httplib
C++ Http/Https服务器和客户端库cpp-httplib

 Windows下Qt Http Server例子

pro文件
SOURCES +=         main.cpp

HEADERS +=     httplib.h

LIBS += -lWs2_32
main.cpp
#include <httplib.h>
using namespace httplib;

void wuhan(const Request &req, Response &res)
{
    printf("httplib server recv a req: %s\n ", req.path.c_str() );
    res.set_content("<html>  \
                        <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"> \
                        <h1> 武汉, 加油!</h1></html>",
                    "text/html");
    res.status = 200;
}

int main(void)
{
    using namespace httplib;

    Server svr;
    svr.set_base_dir("./");

/// Get
svr.Get("/wuhan", wuhan);


    svr.Get("/hi", [](const Request& req, Response& res) {
        res.set_content("Hello World!", "text/plain");
    });

    svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
        auto numbers = req.matches[1];
        res.set_content(numbers, "text/plain");
    });

    svr.Get("/body-header-param", [](const Request& req, Response& res) {
        if (req.has_header("Content-Length")) {
            auto val = req.get_header_value("Content-Length");
        }
        if (req.has_param("key")) {
            auto val = req.get_param_value("key");
        }
        res.set_content(req.body, "text/plain");
    });

    svr.Get("/stop", [&](const Request& req, Response& res) {
        svr.stop();
    });

    /// listen
    svr.listen("localhost", 1234);
}

浏览器输入:localhost:1234 
默认打开当前目录下的index.html页面。

C++ Http/Https服务器和客户端库cpp-httplib

C++ Http/Https服务器和客户端库cpp-httplib

VS Https Server例子

首先需要下载安装OpenSSL,请自行百度
openssl 生成公钥、密钥及.pem文件
使用openssl 生成免费证书
使用openssl生成https证书
Node.js创建自签名的HTTPS服务器

PEMCRT文件:
openssl x509 -outform der -in your-cert.pem -out your-cert.crt

C++ Http/Https服务器和客户端库cpp-httplib

https服务端:

#include <chrono>
#include <cstdio>
#include <httplib.h>

#define SERVER_CERT_FILE "./cert.pem"
#define SERVER_PRIVATE_KEY_FILE "./key.pem"

using namespace httplib;

std::string dump_headers(const Headers &headers) {
  std::string s;
  char buf[BUFSIZ];

  for (auto it = headers.begin(); it != headers.end(); ++it) {
    const auto &x = *it;
    snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
    s += buf;
  }

  return s;
}

std::string log(const Request &req, const Response &res) {
  std::string s;
  char buf[BUFSIZ];

  s += "================================\n";

  snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
           req.version.c_str(), req.path.c_str());
  s += buf;

  std::string query;
  for (auto it = req.params.begin(); it != req.params.end(); ++it) {
    const auto &x = *it;
    snprintf(buf, sizeof(buf), "%c%s=%s",
             (it == req.params.begin()) ? ‘?‘ : ‘&‘, x.first.c_str(),
             x.second.c_str());
    query += buf;
  }
  snprintf(buf, sizeof(buf), "%s\n", query.c_str());
  s += buf;

  s += dump_headers(req.headers);

  s += "--------------------------------\n";

  snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
  s += buf;
  s += dump_headers(res.headers);
  s += "\n";

  if (!res.body.empty()) { s += res.body; }

  s += "\n";

  return s;
}

int main(void) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
#else
  Server svr;
#endif

  if (!svr.is_valid()) {
    printf("server has an error...\n");
    return -1;
  }

  svr.Get("/", [=](const Request & /*req*/, Response &res) {
    res.set_redirect("/hi");
  });

  svr.Get("/hi", [](const Request & /*req*/, Response &res) {
    res.set_content("Hello World!\n", "text/plain");
  });

  svr.Get("/slow", [](const Request & /*req*/, Response &res) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    res.set_content("Slow...\n", "text/plain");
  });

  svr.Get("/dump", [](const Request &req, Response &res) {
    res.set_content(dump_headers(req.headers), "text/plain");
  });

  svr.Get("/stop",
          [&](const Request & /*req*/, Response & /*res*/) { svr.stop(); });

  svr.set_error_handler([](const Request & /*req*/, Response &res) {
    const char *fmt = "<p>Error Status: <span style=‘color:red;‘>%d</span></p>";
    char buf[BUFSIZ];
    snprintf(buf, sizeof(buf), fmt, res.status);
    res.set_content(buf, "text/html");
  });

  svr.set_logger([](const Request &req, const Response &res) {
    printf("%s", log(req, res).c_str());
  });

  svr.listen("localhost", 8080);

  return 0;
}

Https客户端:

#include <httplib.h>
#include <iostream>

//#define CA_CERT_FILE "./ca-bundle.crt"
#define CA_CERT_FILE "./cacert.crt"

using namespace std;

int main(void) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  httplib::SSLClient cli("localhost", 8080);
  // httplib::SSLClient cli("google.com");
  // httplib::SSLClient cli("www.youtube.com");
  cli.set_ca_cert_path(CA_CERT_FILE);
  cli.enable_server_certificate_verification(true);
#else
  httplib::Client cli("localhost", 8080);
#endif

  auto res = cli.Get("/hi");
  if (res) {
    cout << res->status << endl;
    cout << res->get_header_value("Content-Type") << endl;
    cout << res->body << endl;
  } else {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
    auto result = cli.get_openssl_verify_result();
    if (result) {
      cout << "verify error: " << X509_verify_cert_error_string(result) << endl;
    }
#endif
  }

  return 0;
}

关于使用SSL的工程配置说明:
1、通过宏开关CPPHTTPLIB_OPENSSL_SUPPORT控制是否使用Https
2、若使用Https,加入openssl包含路径:C:\OpenSSL-Win64\include,加入openssl的导入库路径C:\OpenSSL-Win64\lib,并链接libcrypto.liblibssl.libopenssl.lib

浏览器访问:

C++ Http/Https服务器和客户端库cpp-httplib
简单学习,进攻参考!

相关推荐