C++编程: 基于cpp-httplib和nlohmann/json实现简单的HTTP Server

文章目录

    • [0. 引言](#0. 引言)
    • [1. 完整实例代码](#1. 完整实例代码)
    • [2. 关键实现](#2. 关键实现)
    • [3. 运行与测试](#3. 运行与测试)

0. 引言

本文基于 cpp-httplibnlohmann/json 实现简单的 HTTPS Server 实例代码,这两个库均是head-only的。

1. 完整实例代码

如下实例程序修改自example/server.cc

cpp 复制代码
#include <httplib.h>

#include <chrono>
#include <cstdio>
#include <nlohmann/json.hpp>

using namespace httplib;
using json = nlohmann::json;

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

json dump_headers_json(const Headers &headers) {
  json j;
  for (const auto &x : headers) {
    j[x.first] = x.second;
  }
  return j;
}

json log_json(const Request &req, const Response &res) {
  json j;

  j["request"]["method"] = req.method;
  j["request"]["version"] = req.version;
  j["request"]["path"] = req.path;

  json query_params = json::object();
  for (const auto &x : req.params) {
    query_params[x.first] = x.second;
  }
  j["request"]["query_params"] = query_params;

  j["request"]["headers"] = dump_headers_json(req.headers);

  j["response"]["status"] = res.status;
  j["response"]["version"] = res.version;
  j["response"]["headers"] = dump_headers_json(res.headers);
  j["response"]["body"] = res.body;

  return j;
}

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) {
    json headers_json = dump_headers_json(req.headers);
    res.set_content(headers_json.dump(4), "application/json");
  });

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

  svr.set_error_handler([](const Request & /*req*/, Response &res) {
    json j;
    j["error"]["status"] = res.status;
    j["error"]["message"] = "An error occurred.";
    res.set_content(j.dump(4), "application/json");
  });

  svr.set_logger([](const Request &req, const Response &res) {
    json log_data = log_json(req, res);
    printf("%s\n", log_data.dump(4).c_str());
  });

  svr.listen("localhost", 8080);

  return 0;
}

2. 关键实现

  • 自签名证书(开发/测试用途)

    SSL 服务器需要证书和私钥文件。使用 OpenSSL 生成一个自签名证书:

    bash 复制代码
    openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

文件说明

- `cert.pem`:服务器的自签名证书,包含公钥。
- `key.pem`:服务器的私钥,用于加密。
  • 配置 SSL Server
    httplib 提供了 SSLServer 类,配置方法如下:

    cpp 复制代码
    SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
    • SERVER_CERT_FILE:证书文件路径。
    • SERVER_PRIVATE_KEY_FILE:私钥文件路径。
  • JSON 格式化响应

    使用 nlohmann/json 将数据格式化为 JSON:

    cpp 复制代码
    res.set_content(headers_json.dump(4), "application/json");
    • headers_json.dump(4):将 JSON 对象格式化为字符串,缩进 4 空格。
  • 日志记录

    将每次请求和响应记录为 JSON 格式的日志:

    cpp 复制代码
    svr.set_logger([](const Request &req, const Response &res) {
        json log_data = log_json(req, res);
        printf("%s\n", log_data.dump(4).c_str());
    });
  • 错误处理

    自定义错误响应:

    cpp 复制代码
    svr.set_error_handler([](const Request & /*req*/, Response &res) {
        json j;
        j["error"]["status"] = res.status;
        j["error"]["message"] = "An error occurred.";
        res.set_content(j.dump(4), "application/json");
    });

3. 运行与测试

  • 编译代码

    确保链接 nlohmann/jsonhttplib

    bash 复制代码
    g++ server.cpp -o server -std=c++14 -lssl -lcrypto
  • 运行服务

    bash 复制代码
    ./server
  • 测试 API

    使用 curl 测试:

    bash 复制代码
    $ curl -k https://localhost:8080/dump                                                                                                                                                
    {
        "Accept": "*/*",
        "Host": "localhost:8080",
        "LOCAL_ADDR": "127.0.0.1",
        "LOCAL_PORT": "8080",
        "REMOTE_ADDR": "127.0.0.1",
        "REMOTE_PORT": "41542",
        "User-Agent": "curl/7.68.0"
    }% 

    参数说明:

    • -k:忽略自签名证书的警告。
  • 在浏览器上打开

相关推荐
liupenglove几秒前
protobuf c++开发快速上手指南
开发语言·c++
卜及中1 小时前
【数据结构】B树家族解析:B树、B+树与B*树的理论与B树插入实现(C++)
开发语言·数据结构·c++·b树
m0_748247802 小时前
如何使用Node.js快速创建本地HTTP服务器并实现异地远程访问
服务器·http·node.js
PluviophileDD3 小时前
【笔记】C语言转C++
c语言·c++
獨枭3 小时前
MFC 自定义编辑框:打造灵活的数据输入控件
c++·mfc
逆袭之路6664 小时前
浅谈右值引用 移动语义 完美转发 std::move std::forward,窥探模板元编程的一角
c++
安於宿命4 小时前
【Linux】文件系统
linux·服务器·c++
oioihoii4 小时前
C++ 中 std::array<int, array_size> 与 std::vector<int> 的深入对比
开发语言·c++
OTWOL4 小时前
预处理基础指南
开发语言·数据结构·c++·算法
搬砖的果果4 小时前
数据采集,如何选择适合自己的HTTP代理?
网络·网络协议·http