本文最后更新于 2024-10-18,文章内容距离上一次更新已经过去了很久啦,可能已经过时了,请谨慎参考喵。

title: Cpp构建简单HttpServer服务器
top_img: false
tags:
  - C++
  - Http
categories:
  - 编程语言
cover: false
abbrlink: a19c06b7
date: 2023-12-10 20:04:12
copyright:
comments:

前言

无聊刷B站的时候,偶尔之间看到了bcbooo大佬的视频,在做国产的类Aspen模拟软件视频,然后深深的陷入了其中,无法自拔。

然后自己也想学习一下,大佬推荐后端使用C++语言写,刚好自己有点C语言的基础,稍微折腾了一下,先实现一个简单的HttpServer,毕竟要想学会解方程,不得从1+1=2开始学习(不是)。

在此特别感谢我一个朋友对我的帮助,李某某。

正文

首先,C++构建HttpServer可以使用不同的第三方库去实现,比如我之前找资料的时候了解到的Poco库(这个库因为对小白不友好,折腾了好几天不会编译,还是放弃了)。

我们使用C++官方的httplib库来实现,引入第三方库就不赘述了,其中我还踩坑了,可以在这里看到:Clion引入第三方库

后端

话不多说,直接上代码:

//引用标准库
#include <iostream>
#include <format>
//引入第三方 httplib 库
#include "./httplib/httplib.h"

int main (void) {
    //注册一个 httpserver
    httplib::Server svr;
    
    //注册一个测试 api
    svr.Get("/test", [](const httplib::Request& req, httplib::Response& res) {
        //取出 token 的值
        auto token{ req.get_header_value("token") };
        //打印 token 的值
        std::cout << token << std::endl;
        //testAPI 访问成功时,返回前端 msg信息
        res.set_content(R"-({"message":"Hello World!"})-", "application/json");
    });
    
    //当访问 test 的请求头中带有 token 参数,在后端打印 OPTIONS ACCESS 以及 token 的值
    svr.Options("/test", [](const httplib::Request& req, httplib::Response& res) {
        std::cout << "OPTIONS ACCESS" << std::endl;
        res.status = 200;
    });
    
	//注册一个停止服务器的api
    svr.Get("/stop", [&](const httplib::Request& req, httplib::Response& res) {
        svr.stop();
    });
	//监听 localHost 的 1234 端口
    svr.listen("0.0.0.0", 1234);
    return 0;
}

CMakeLists 编写:

#cmake 版本
cmake_minimum_required(VERSION 3.26)
#项目名称
project(blogCppTest)
#编译版本
set(CMAKE_CXX_STANDARD 23)
#引入第三方库
add_subdirectory(httplib)
#编译文件
add_executable(blogCppTest main.cpp)
#编译库链接
target_link_libraries(blogCppTest httplib)

好的,现在我们的测试api就已经完成了,编译,运行,访问 http://127.0.0.1:1234/test

访问 http://127.0.0.1:1234/stop 服务器就会停机。

但是我们发现后端并没有打印出我们想要的信息:

这是因为我们并没有传给后端信息,接下来就写一下前端代码。

前端

话不多说,直接上代码:

<p>
    调用服务器的请求接口
</p>
<form action="javascript:testCpp();" method="get">
    <input type="submit" value="测试服务器状态">
</form>
<script>
    function testCpp() {
        $.ajax({
            url: 'http://127.0.0.1:1234/test',
            method: 'GET',
            headers: {
                'token': 'Client Link Success'
            },
            success: function() {
                console.log("服务器已启动");
            }
        });
    }
</script>

记得引用jQuery库哦~

接下来编译执行刚才的cpp,同时用浏览器打开该html文件,点击测试服务器状态按钮:

报错了,原来是遇到跨域请求的问题了,什么是跨域请求问题,请自行百度;

在cpp文件中加入如下代码:

//解决跨域请求的问题,通过CORS声明HTTP头信息
svr.set_default_headers({
    { "Access-Control-Allow-Origin", "*" },
    { "Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"},
    { "Access-Control-Max-Age", "3600"},
    { "Access-Control-Allow-Headers", "*"},
    { "Content-Type", "application/json;charset=utf-8"}
});

需要注意的是,由于C++代码执行顺序的问题,需要将该段代码写在api后面,也就是下图代码的下方:

然后重新编译,运行:

已经访问成功了!!!

1+1=2

接下来我们实现一个1+1等于2吧

直接上代码,后端:

void calc(const httplib::Request& req, httplib::Response& res)
{
    // 获取请求中的参数 num1 和 num2
    if (req.has_param("num1") && req.has_param("num2"))
    {
        // 获取到数值
        std::string num1 = req.get_param_value("num1");
        std::string num2 = req.get_param_value("num2");
        // 转换字符型数值为整型,并进行计算
        std::string result = std::to_string(std::stoi(num1) + std::stoi(num2));
        // 后端打印两个数值
        std::cout << std::format("num1: {}, num2: {}", num1, num2) << std::endl;
        // 返回数值给前端
        res.set_content(result, "text/plain");
        return;
        // 处理请求的逻辑结束
    }
    res.set_content("num1 or num2 not found", "text/plain");
}

在cpp中添加该函数,注意要在main函数前面哦;

在main函数中添加下面这个api:

svr.Post("/calc", calc);

再来写个前端:

<form action="javascript:calc_use_request_ajax();" method="post" name="myForm_use_request">
    <label>
        <input type="text" name="num1" placeholder="Enter first number">
    </label>
    <label>
        <input type="text" name="num2" placeholder="Enter second number">
    </label>
    <input type="submit" value="Submit">
    <input type="reset" value="Reset">
</form>
<span id="result_from_request">The result will be displayed here.</span>

<script>
    function calc_use_request_ajax() {
        $.ajax({
            url: "http://127.0.0.1:1234/calc",
            method: 'POST',
            data: {
                num1: document.forms["myForm_use_request"]["num1"].value,
                num2: document.forms["myForm_use_request"]["num2"].value
            },
            success: function (response) {
                document.getElementById("result_from_request").innerHTML = response;
                console.log("simpleAdd success");
            },
            error: function () {
                console.error();
            }
        });
    }
</script>

让我们运行起来吧:

现在你已经学会了1+1=2了,那么请开发一个大型的工业计算APP吧(不是)~

注意

如果服务器配置语句写在另一个cpp文件中,主main.cpp文件中只是调用服务器的函数的话,主main.cpp的 #include 必须包含 httplib.h 引用,如图所示: