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

相关推荐
Fireworkitte34 分钟前
gRPC和http长轮询
网络·网络协议·http
还债大湿兄2 小时前
《C++内存泄漏8大战场:Qt/MFC实战详解 + 面试高频陷阱破解》
c++·qt·mfc
珊瑚里的鱼5 小时前
LeetCode 692题解 | 前K个高频单词
开发语言·c++·算法·leetcode·职场和发展·学习方法
AI+程序员在路上5 小时前
QTextCodec的功能及其在Qt5及Qt6中的演变
开发语言·c++·qt
Risehuxyc6 小时前
C++卸载了会影响电脑正常使用吗?解析C++运行库的作用与卸载后果
开发语言·c++
不超限7 小时前
IIS错误:Service Unavailable HTTP Error 503. The service is unavailable.
网络·网络协议·http
景彡先生8 小时前
C++编译期计算:常量表达式(constexpr)全解析
服务器·c++
tan77º9 小时前
【Linux网络编程】应用层自定义协议与序列化
linux·运维·服务器·网络·c++·tcp/ip
悠哉清闲10 小时前
Android Studio C++/JNI/Kotlin 示例 三
c++·kotlin·android studio
AI迅剑10 小时前
模块三:现代C++工程实践(4篇)第二篇《性能调优:Profile驱动优化与汇编级分析》
汇编·c++