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:忽略自签名证书的警告。
  • 在浏览器上打开

相关推荐
Tairitsu_H4 小时前
[C++] 深入理解红黑树:封装set与map
开发语言·c++·set·map·红黑树·模拟实现
HugoStudio_SWAN5 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
会周易的程序员6 小时前
5Draft(五帝)测试报告
服务器·c++·分布式·raft·共识算法·共识·算力服务器
UIU1147 小时前
scanf与cout的误区:探究其内部的机制
c++·学习·c#·scanf
闻缺陷则喜何志丹7 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统
bnmoel7 小时前
C++ 基础入门篇(一):命名空间,输入&输出,缺省参数,函数重载
c++·函数重载·语法·命名空间·缺省参数
Zixhy8 小时前
多点巡检机器人项目技术总结
linux·c++·机器人·自动驾驶
Pointer Pursuit9 小时前
C++11特性(二)
前端·c++·算法
tudousisi22210 小时前
CSP 第3题训练 Day 5|CSP202509C HTTP 头信息|Blog A
c++
闻缺陷则喜何志丹11 小时前
【动态规划】P10726 [GESP202406 八级] 空间跳跃|普及+
c++·算法·动态规划·洛谷