前言

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

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

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

正文

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

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

后端

话不多说,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//引用标准库
#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 编写:

1
2
3
4
5
6
7
8
9
10
11
12
#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 服务器就会停机。

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

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

前端

话不多说,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<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文件中加入如下代码:

1
2
3
4
5
6
7
8
//解决跨域请求的问题,通过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吧

直接上代码,后端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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:

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

再来写个前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<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 引用,如图所示: