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

相关推荐
游戏开发爱好者839 分钟前
iOS重构期调试实战:架构升级中的性能与数据保障策略
websocket·网络协议·tcp/ip·http·网络安全·https·udp
十五年专注C++开发44 分钟前
CMake基础:条件判断详解
c++·跨平台·cmake·自动化编译
QuantumStack3 小时前
【C++ 真题】P1104 生日
开发语言·c++·算法
天若有情6733 小时前
01_软件卓越之道:功能性与需求满足
c++·软件工程·软件
whoarethenext3 小时前
使用 C++/OpenCV 和 MFCC 构建双重认证智能门禁系统
开发语言·c++·opencv·mfcc
Jay_5155 小时前
C++多态与虚函数详解:从入门到精通
开发语言·c++
xiaolang_8616_wjl5 小时前
c++文字游戏_闯关打怪
开发语言·数据结构·c++·算法·c++20
FrostedLotus·霜莲6 小时前
C++主流编辑器特点比较
开发语言·c++·编辑器
liulilittle10 小时前
深度剖析:OPENPPP2 libtcpip 实现原理与架构设计
开发语言·网络·c++·tcp/ip·智能路由器·tcp·通信
2501_9160137411 小时前
iOS 多线程导致接口乱序?抓包还原 + 请求调度优化实战
websocket·网络协议·tcp/ip·http·网络安全·https·udp