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

相关推荐
2501_915921431 天前
“HTTPS 个人化”实战,个人站点与设备调试的部署、验证与抓包排查方法
网络协议·http·ios·小程序·https·uni-app·iphone
oioihoii1 天前
深入理解 C++ 现代类型推导:从 auto 到 decltype 与完美转发
java·开发语言·c++
报错小能手1 天前
项目——基于C/S架构的预约系统平台 (1)
开发语言·c++·笔记·学习·架构
lingran__1 天前
算法沉淀第十天(牛客2025秋季算法编程训练联赛2-基础组 和 奇怪的电梯)
c++·算法
好好研究1 天前
JAVAEE知识整理之AJAX、JSON
ajax·java-ee·json·1024程序员节
oioihoii1 天前
当无符号与有符号整数相遇:C++中的隐式类型转换陷阱
java·开发语言·c++
Yupureki1 天前
从零开始的C++学习生活 13:红黑树全面解析
c语言·数据结构·c++·学习·visual studio
2401_876221341 天前
Euler
c++·数学·算法
赵杰伦cpp1 天前
C++的继承机制精讲
java·开发语言·c++·后端
tongsound1 天前
记录一次崩溃问题排查过程(gtsam库相关,avx)
linux·c++