C/C++ HTTP 服务:常用方法与实现方式全解析

HTTP 作为互联网通信的核心协议,是 C/C++ 后端开发中构建网络服务的基础能力。本文将从 HTTP 核心请求方法入手,详解 C/C++ 实现 HTTP 服务的主流方式,结合实战代码示例,帮助开发者快速掌握从基础到进阶的实现思路。


一、HTTP的用途

不管是现在大火的大模型接口调用、Token 计算传输,还是咱们做网站时的前后端交互、拿数据、传数据,底层跑的全都是 HTTP 请求。无论是大模型通过 API 完成文本生成、Token 流式返回,还是前端请求后端接口获取数据、提交表单,亦或是网页加载图片、样式、脚本等静态资源,本质上都是遵循 HTTP/HTTPS 的请求 - 响应模式。它以简洁、标准化的通信方式,成为互联网应用的通用语言,覆盖了从大模型服务Web 开发的绝大多数场景,支撑起了各类线上功能的稳定运行与数据交互。

二、HTTP 核心请求方法

在 C/C++ HTTP 服务开发中,无需实现所有 HTTP 方法,只需聚焦业务高频使用的核心方法,以下是服务端必须支持的 6 种核心方法及处理逻辑:

HTTP 方法 核心用途
GET 获取资源(如查询数据)
POST 提交数据(如创建资源)
PUT 全量更新资源
PATCH 部分更新资源
DELETE 删除资源
OPTIONS 跨域预检

三、HTTP 接收的数据格式(Content-Type)

数据格式 用途介绍
application/json 传 JSON 对象,现在接口最主流
application/x-www-form-urlencoded 普通表单格式:key1=val1&key2=val2,浏览器原生表单默认格式
multipart/form-data 全上传文件专用,可同时传文本 + 文件
text/plain 纯文本
application/octet-stream 二进制流(下载文件、传字节流用)

四、HTTP数据交互过程

复制代码
┌─────────────────┐
│  客户端         │  (浏览器/前端/大模型调用端)
│  - 发起HTTP请求 │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────┐
│ HTTP请求报文                         │
│  请求行:GET/POST + 接口地址 + 协议   │
│  请求头:Content-Type/Cookie等       │
│  请求体:提交的参数/文件/Token等     │
└────────┬─────────────────────────────┘
         │
         ▼
┌─────────────────┐
│  HTTP服务端     │  (后端服务器)
│  解析请求       │
│  处理业务逻辑   │
│  生成响应数据   │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────┐
│ HTTP响应报文                         │
│  状态行:200成功/404失败/500错误     │
│  响应头:Access-Control-Allow-Origin  │
│  响应体:JSON/HTML/图片/文本等数据    │
└────────┬─────────────────────────────┘
         │
         ▼
┌─────────────────┐
│  客户端         │
│  解析响应数据   │
│  渲染展示/更新  │
└─────────────────┘

五、基于Mongoose的封装

Mongoose 是一个面向 C/C++ 的网络库。它提供事件驱动的非阻塞 支持TCP、UDP、HTTP、WebSocket、MQTT及其他协议的API。它是设计好的 用于连接设备并使其上线。自2004年起上市,使用过 通过大量开源和商业产品------它甚至运行在 国际空间站!

代码位置:Mongoose Github

至于这里为什么使用mongoose,因为使用方便,不需要编译库,只需要将mongoose.hmongoose.c放到项目中就可直接使用。

1 Mongoose服务端代码

下面是基于Mongoose封装的一个HTTP服务器:

c++ 复制代码
////MGSrvUtil.hpp
#include "mongoose.h"
#include <thread>
#include <string>
#include <vector>

class MGSrvUtil
{
public:
	MGSrvUtil()
	{
		m_sConnection = nullptr;
		memset(&m_mgMessage, 0, sizeof(m_mgMessage));

        m_nMGDebugLevel = MG_LL_INFO;
        m_bActivate = false;
	}
	~MGSrvUtil()
	{


	}
public:
	
    /////enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
    void InitParameter(const char* saveFilePath,int debugLevel);
    /////example:"http://0.0.0.0:8000";
	void StartMGHttpSrv(const char* http_addr);
    void StopHttpSrv()
    {
        m_bActivate = false;
    }



private:
	//MG Function
	static void mg_callback_recv(struct mg_connection* c, int ev, void* ev_data);
	void HandleCallbackRecv(struct mg_connection* c, int ev, void* ev_data);
    void ThreadStartSrv(const char* http_addr);

    void HandleHttpRequest(struct mg_connection* c, struct mg_http_message* hm);
    ////////////HTTP Method Handle
    void HandleGetRequest(struct mg_connection* c, struct mg_http_message* hm);
    void HandlePostRequest(struct mg_connection* c, struct mg_http_message* hm);
    void HandlePutRequest(struct mg_connection* c, struct mg_http_message* hm);
    void HandlePatchRequest(struct mg_connection* c, struct mg_http_message* hm);
    void HandleDeleteRequest(struct mg_connection* c, struct mg_http_message* hm);
    void HandleOptionsRequest(struct mg_connection* c, struct mg_http_message* hm);




private:
	//MG Srv  Parameters
	struct mg_mgr m_mgMessage;
	struct mg_connection* m_sConnection;
    const char* m_fileSaveDir = NULL;
    int m_nMGDebugLevel;
    bool m_bActivate;



};
void MGSrvUtil::InitParameter(const char* saveFilePath, int debugLevel = MG_LL_INFO)
{
    m_fileSaveDir = saveFilePath;
    m_nMGDebugLevel = debugLevel;
}
void MGSrvUtil::ThreadStartSrv(const char* http_addr)
{
    mg_log_set(m_nMGDebugLevel);
    mg_mgr_init(&m_mgMessage);
    if ((m_sConnection = mg_http_listen(&m_mgMessage, http_addr, mg_callback_recv, this)) == NULL)
    {
        MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
            http_addr));
        exit(EXIT_FAILURE);
    }

    // Start infinite event loop
    MG_INFO(("Mongoose version : v%s", MG_VERSION));
    MG_INFO(("Listening on     : %s", http_addr));
    MG_INFO(("Upload dir       : %s", m_fileSaveDir ? m_fileSaveDir : "(unset)"));

    while (true)
    {
        mg_mgr_poll(&m_mgMessage, 1000);
        if (!m_bActivate)
        {
            mg_mgr_free(&m_mgMessage);
            break;
        }
    }
    


}
void MGSrvUtil::StartMGHttpSrv(const char* http_addr)
{
    m_bActivate = true;
    std::thread start(&MGSrvUtil::ThreadStartSrv, this, http_addr);
    start.detach();

}
void MGSrvUtil::mg_callback_recv(struct mg_connection* c, int ev, void* ev_data)
{
	MGSrvUtil* instance = (MGSrvUtil*)c->fn_data;
	instance->HandleCallbackRecv(c, ev, ev_data);
}
void MGSrvUtil::HandleCallbackRecv(struct mg_connection* c, int ev, void* ev_data)
{
    switch (ev) 
    {
    case MG_EV_HTTP_MSG: 
    {
        struct mg_http_message* hm = static_cast<struct mg_http_message*>(ev_data);
        HandleHttpRequest(c, hm);
        break;
    }
    case MG_EV_CLOSE: 
    {

        MG_DEBUG(("Connection closed"));
        break;
    }
    case MG_EV_ERROR: 
    {

        MG_ERROR(("Connection error: %s", (char*)ev_data));
        break;
    }
    default:
        break;
    }

}
void MGSrvUtil::HandleHttpRequest(struct mg_connection* c, struct mg_http_message* hm) 
{

    std::string method(hm->method.buf, hm->method.len);

    if (method == "GET") 
    {
        HandleGetRequest(c, hm);
    }
    else if (method == "POST") 
    {
        std::cout << "Post Request Recv!!" << std::endl;
        HandlePostRequest(c, hm);
    }
    else if (method == "PUT") 
    {
        HandlePutRequest(c, hm);
    }
    else if (method == "PATCH") 
    {
        HandlePatchRequest(c, hm);
    }
    else if (method == "DELETE") 
    {
        HandleDeleteRequest(c, hm);
    }
    else if (method == "OPTIONS") 
    {
        HandleOptionsRequest(c, hm);
    }
    else 
    {
        mg_http_reply(c, 405, "Content-Type: text/plain\r\n", "%s", "Method Not Allowed");
    }

    MG_INFO(("%.*s %.*s %lu -> %.*s %lu",
        hm->method.len, hm->method.buf,
        hm->uri.len, hm->uri.buf,
        hm->body.len,
        3, c->send.buf + 9, c->send.len));
}

// ------------------------------ HTTP Method Handle ------------------------------
void MGSrvUtil::HandleGetRequest(struct mg_connection* c, struct mg_http_message* hm) 
{
    mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}

void MGSrvUtil::HandlePostRequest(struct mg_connection* c, struct mg_http_message* hm) 
{

    std::string full_uri(hm->uri.buf, hm->uri.len);
    std::cout << "Full URI: " << full_uri << std::endl;

    if ((mg_match(hm->uri, mg_str("/test"), NULL)))
    {
        std::cout << "test" << std::endl;

        mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "/test success");
        // Log request
        //MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.buf,
        //    hm->uri.len, hm->uri.buf, hm->body.len, 3, c->send.buf + 9,
        //    c->send.len));
    }
    else if((mg_match(hm->uri, mg_str("/upload"), NULL)))
    {
        mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "/upload success");
        //std::string base64_data(hm->body.buf, hm->body.len);

        std::cout << "upload" << std::endl;


    }
    else
    {
        mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "success");
        std::cout << "Not Found Method" << std::endl;
    }
    

}

void MGSrvUtil::HandlePutRequest(struct mg_connection* c, struct mg_http_message* hm) 
{
    mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}

void MGSrvUtil::HandlePatchRequest(struct mg_connection* c, struct mg_http_message* hm) 
{
    mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}

void MGSrvUtil::HandleDeleteRequest(struct mg_connection* c, struct mg_http_message* hm) 
{
    mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}

void MGSrvUtil::HandleOptionsRequest(struct mg_connection* c, struct mg_http_message* hm) 
{

    mg_http_reply(c, 200,
        "Access-Control-Allow-Origin: *\r\n"
        "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
        "Access-Control-Allow-Headers: Content-Type\r\n",
        "");

}

2 Mongoose客户端代码

复制代码
//MGCltUtil.hpp
#pragma once
#include "mongoose.h"
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <atomic>

class MGCltUtil
{
public:
	MGCltUtil()
    {
        mg_mgr_init(&m_mgr);
        m_done = false;
        m_bTimeOut = false;
        m_timeout_ms = 1500;
        m_response_data = "";
        m_response_code = 0;
        m_url = "";

    }
	~MGCltUtil()
    {
        mg_mgr_free(&m_mgr);
    }

public:
	static void callback_client_recv(struct mg_connection* c, int ev, void* ev_data);
	void HandleClientRecv(struct mg_connection* c, int ev, void* ev_data);

	// 发送HTTP请求,支持自定义method、content_type、body
	// method: "GET", "POST", "PUT", "DELETE" 等
	// content_type: "application/json", "text/plain", "application/x-www-form-urlencoded" 等
	// body: 请求体内容,GET请求可传空字符串
	bool SendRequest(const std::string& url, const std::string& method = "GET",
		const std::string& content_type = "application/json",
		const std::string& body = "", uint64_t timeout_ms = 1500);

	    // new add,upload image
    bool UploadJpegFile(const std::string& url,
        const std::string& file_path,
        const std::vector<uint8_t>& jpeg_data,
        uint64_t timeout_ms = 30000);

	// 获取响应数据
	std::string GetResponseData() const { return m_response_data; }
	// 获取响应状态码
	int GetResponseCode()  { return m_response_code; }

private:
	struct mg_mgr m_mgr;
	bool m_done;
	bool m_bTimeOut;

	uint64_t m_timeout_ms;
	std::string m_response_data;
	int m_response_code;
	std::string m_url;
	std::string m_method;
	std::string m_content_type;
	std::string m_body;
	
	///upload image parameters
	std::vector<uint8_t> m_upload_data;
    std::string m_file_name;
};

bool MGCltUtil::SendRequest(const std::string& url, const std::string& method,
    const std::string& content_type, const std::string& body, uint64_t timeout_ms)
{
    m_done = false;
    m_bTimeOut = false;
    m_url = url;
    m_method = method;
    m_content_type = content_type;
    m_body = body;
    m_timeout_ms = timeout_ms;
    m_response_data = "";
    m_response_code = 0;

    if (m_url.find("http://") != 0 && m_url.find("https://") != 0)
    {
        std::cout << "Invalid URL format, should start with http:// or https://" << std::endl;
        return false;
    }

    mg_http_connect(&m_mgr, m_url.c_str(), callback_client_recv, this);
    while (!m_done)
    {
        mg_mgr_poll(&m_mgr, 50);
        if (m_bTimeOut)
        {
            std::cout << "Connect Timeout!!!" << std::endl;
            return false;
        }
    }
    return true;
}
// multipart/form-data JPEG File Upload
bool MGCltUtil::UploadJpegFile(const std::string& url,
    const std::string& file_path,
    const std::vector<uint8_t>& jpeg_data,
    uint64_t timeout_ms)
{
    m_done = false;
    m_bTimeOut = false;
    m_url = url;
    m_timeout_ms = timeout_ms;
    m_response_data = "";
    m_response_code = 0;
    m_upload_data = jpeg_data;

    size_t pos = file_path.find_last_of("/\\");
    m_file_name = (pos == std::string::npos) ? file_path : file_path.substr(pos + 1);

    if (m_url.find("http://") != 0) return false;
    if (jpeg_data.empty()) return false;

    mg_http_connect(&m_mgr, m_url.c_str(), callback_client_recv, this);
    while (!m_done)
    {
        mg_mgr_poll(&m_mgr, 50);
        if (m_bTimeOut) { std::cout << "上传超时" << std::endl; return false; }
    }
    return (m_response_code == 200);
}

void MGCltUtil::callback_client_recv(struct mg_connection* c, int ev, void* ev_data)
{
    MGCltUtil* instance = static_cast<MGCltUtil*>(c->fn_data);
    if (instance != nullptr)
    {
        instance->HandleClientRecv(c, ev, ev_data);
    }
}

void MGCltUtil::HandleClientRecv(struct mg_connection* c, int ev, void* ev_data)
{
    switch (ev)
    {
    case MG_EV_OPEN:
        *(uint64_t*)c->data = mg_millis() + m_timeout_ms;
        break;

    case MG_EV_POLL:
        if (mg_millis() > *(uint64_t*)c->data && (c->is_connecting || c->is_resolving))
        {
            m_bTimeOut = true;
            mg_error(c, "Connect timeout");
        }
        break;

    case MG_EV_CONNECT:
    {
        struct mg_str host = mg_url_host(m_url.c_str());
        int content_length = (int)m_body.size();

        // 发送请求行和Host
        mg_printf(c,
            "%s %s HTTP/1.1\r\n"
            "Host: %.*s\r\n"
            "Content-Type: %.*s\r\n"
            "Content-Length: %d\r\n"
            "Connection: close\r\n",
            m_method.c_str(), mg_url_uri(m_url.c_str()),
            (int)host.len, host.buf,
            (int)m_content_type.size(), m_content_type.c_str(),
            content_length);
        mg_printf(c, "%s", "\r\n");  // 结束头部

        // 发送body
        if (content_length > 0)
        {
            mg_send(c, m_body.c_str(), content_length);
        }
    }
    break;

    case MG_EV_HTTP_MSG:
    {
        struct mg_http_message* hm = (struct mg_http_message*)ev_data;
        m_response_code = mg_http_status(hm);
        m_response_data = std::string(hm->body.buf, hm->body.len);
        std::cout << "Response Status: " << m_response_code << std::endl;
        std::cout << "Response Body: " << m_response_data << std::endl;
        c->is_draining = 1;
        m_done = true;
    }
    break;

    case MG_EV_ERROR:
        m_done = true;
        break;
    }
}
int main(int argc, char* argv[])
{
    MGCltUtil client;

    // GET Method
    client.SendRequest("http://127.0.0.1:1234/test");

    // // POST JSON
    client.SendRequest("http://127.0.0.1:1234//cmd_move", "POST", "application/json", R"({"key":"value"})");

    // // POST Method
    // client.SendRequest("http://127.0.0.1:1234/test", "POST", "application/x-www-form-urlencoded", "name=hello&age=18");

    // // PUT Method
    // client.SendRequest("http://127.0.0.1:1234/api/data", "PUT", "text/plain", "updated content");

    getchar();

    return 0;
}

3 libcurl客户端代码

c++ 复制代码
#include <curl/curl.h>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <atomic>
#include <chrono>

class CurlCltUtil
{
public:
	CurlCltUtil()
	{
		m_done = false;
		m_bTimeOut = false;
		m_timeout_ms = 1500;
		m_response_data = "";
		m_response_code = 0;
		m_url = "";
		m_response_headers = ""; // 新增

		// libcurl 全局初始化(一次即可)
		curl_global_init(CURL_GLOBAL_ALL);
	}

	~CurlCltUtil()
	{
		curl_global_cleanup();
	}

public:
	// 发送HTTP请求,支持自定义method、content_type、body
	bool SendRequest(const std::string& url, const std::string& method = "GET",
		const std::string& content_type = "application/json",
		const std::string& body = "", uint64_t timeout_ms = 1500);

	// 上传JPEG文件(multipart/form-data)
	bool UploadJpegFile(const std::string& url,
		const std::string& file_path,
		const std::vector<uint8_t>& jpeg_data,
		uint64_t timeout_ms = 30000);

	std::string GetResponseData() const { return m_response_data; }
	int GetResponseCode() { return m_response_code; }
	std::string GetResponseHeaders() const { return m_response_headers; }

	void PrintResponse() {
		std::cout << "\n===== HTTP RESPONSE =====\n";
		std::cout << "Status Code: " << m_response_code << "\n\n";
		std::cout << "Headers:\n" << m_response_headers << "\n";
		std::cout << "Body:\n" << m_response_data << "\n";
		std::cout << "=========================\n\n";
	}

private:
	static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s);
	static size_t HeaderCallback(void* contents, size_t size, size_t nmemb, std::string* s); // 新增

private:
	bool m_done;
	bool m_bTimeOut;

	uint64_t m_timeout_ms;
	std::string m_response_data;
	std::string m_response_headers; // 新增
	int m_response_code;
	std::string m_url;
	std::string m_method;
	std::string m_content_type;
	std::string m_body;

	// 上传图片用
	std::vector<uint8_t> m_upload_data;
	std::string m_file_name;
};

// ====================== 实现 ======================

size_t CurlCltUtil::WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s)
{
	size_t newLength = size * nmemb;
	try {
		s->append((char*)contents, newLength);
	}
	catch (std::bad_alloc& e) {
		return 0;
	}
	return newLength;
}

// 新增:接收响应头
size_t CurlCltUtil::HeaderCallback(void* contents, size_t size, size_t nmemb, std::string* s)
{
	size_t newLength = size * nmemb;
	try {
		s->append((char*)contents, newLength);
	}
	catch (std::bad_alloc& e) {
		return 0;
	}
	return newLength;
}

bool CurlCltUtil::SendRequest(const std::string& url, const std::string& method,
	const std::string& content_type, const std::string& body, uint64_t timeout_ms)
{
	m_done = false;
	m_bTimeOut = false;
	m_url = url;
	m_method = method;
	m_content_type = content_type;
	m_body = body;
	m_timeout_ms = timeout_ms;
	m_response_data.clear();
	m_response_headers.clear(); // 新增
	m_response_code = 0;

	CURL* curl = curl_easy_init();
	if (!curl) return false;

	// 设置URL
	curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());

	// 设置请求方法
	if (m_method == "POST")
		curl_easy_setopt(curl, CURLOPT_POST, 1L);
	else if (m_method == "PUT")
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
	else if (m_method == "DELETE")
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
	else
		curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);

	// 超时
	curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)timeout_ms);

	// 响应数据接收
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &m_response_data);

	// 新增:接收响应头
	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
	curl_easy_setopt(curl, CURLOPT_HEADERDATA, &m_response_headers);

	// POST/PUT 数据
	struct curl_slist* headers = NULL;
	if (!m_content_type.empty()) {
		std::string h = "Content-Type: " + m_content_type;
		headers = curl_slist_append(headers, h.c_str());
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	}

	if ((m_method == "POST" || m_method == "PUT") && !m_body.empty()) {
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, m_body.c_str());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)m_body.size());
	}

	// 执行请求
	CURLcode res = curl_easy_perform(curl);

	// 获取状态码
	curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &m_response_code);

	// 清理
	if (headers) curl_slist_free_all(headers);
	curl_easy_cleanup(curl);

	m_done = true;

	if (res != CURLE_OK) {
		if (res == CURLE_OPERATION_TIMEDOUT)
			m_bTimeOut = true;
		return false;
	}

	return true;
}

// 上传 JPEG(multipart/form-data)
bool CurlCltUtil::UploadJpegFile(const std::string& url,
	const std::string& file_path,
	const std::vector<uint8_t>& jpeg_data,
	uint64_t timeout_ms)
{
	m_done = false;
	m_bTimeOut = false;
	m_url = url;
	m_timeout_ms = timeout_ms;
	m_response_data.clear();
	m_response_headers.clear(); // 新增
	m_response_code = 0;
	m_upload_data = jpeg_data;

	size_t pos = file_path.find_last_of("/\\");
	m_file_name = (pos == std::string::npos) ? file_path : file_path.substr(pos + 1);

	if (m_url.empty() || jpeg_data.empty()) return false;

	CURL* curl = curl_easy_init();
	if (!curl) return false;

	curl_mime* mime = curl_mime_init(curl);
	curl_mimepart* part = curl_mime_addpart(mime);

	curl_mime_name(part, "file");
	curl_mime_filename(part, m_file_name.c_str());
	curl_mime_type(part, "image/jpeg");
	curl_mime_data(part, (const char*)jpeg_data.data(), jpeg_data.size());

	curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
	curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)timeout_ms);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &m_response_data);
	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback); // 新增
	curl_easy_setopt(curl, CURLOPT_HEADERDATA, &m_response_headers); // 新增

	CURLcode res = curl_easy_perform(curl);
	curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &m_response_code);

	curl_mime_free(mime);
	curl_easy_cleanup(curl);
	m_done = true;

	if (res != CURLE_OK) {
		if (res == CURLE_OPERATION_TIMEDOUT) m_bTimeOut = true;
		return false;
	}

	return (m_response_code == 200);
}

// ====================== 测试 main ======================
int main(int argc, char* argv[])
{
	CurlCltUtil client;

	// GET
	bool ret = client.SendRequest("http://192.168.0.128:1234/test");
	if (ret) {
		client.PrintResponse(); // 直接打印 code + header + body
	}

	// POST JSON
	//client.SendRequest("http://192.168.1.2:1234/cmd_move", "POST", "application/json", R"({"key":"value"})");
	//client.PrintResponse();

	getchar();
	return 0;
}

六、基于libhv的封装

基于libhv的封装本来是想写一块的,但是考虑到需要编译,安装,篇幅太长于是新开了一篇文章:
libhv 安装与使用全流程教程

七、上述代码库对比

项目 curl/libcurl libhv mongoose
核心定位 命令行工具 + 客户端传输库 全功能高性能网络框架(客户端 + 服务端) 极简嵌入式网络库(客户端 + 服务端)
设计目标 支持最多协议、最稳定的跨平台传输 高性能、易用、全栈网络开发 极小体积、零依赖、嵌入式友好
开源协议 curl 许可证(类似 MIT,宽松) BSD 3-Clause GPLv2 / 商业双授权
是否可商用 完全可商用,无版权污染 完全可商用,无版权污染 GPL 版不可闭源商用;需买商业授权

总结

HTTP是C/C++后端开发、互联网通信的核心协议,贯穿前后端交互、大模型接口调用等各类场景,掌握HTTP请求方法、数据格式和通信流程,是搭建网络服务的基础。本文梳理了高频HTTP请求方法与常用数据格式,拆解了完整的HTTP交互流程,还提供了Mongoose服务端、客户端以及libcurl客户端的实战封装代码,上手即用、适配工程开发。同时对比了curl/libcurl、libhv、Mongoose三大库的差异,开发者可按需选择:Mongoose轻量零依赖,适合嵌入式场景;libhv高性能全能,适合高并发服务;libcurl协议齐全、稳定易用,专攻客户端传输,助力开发者高效搭建HTTP服务。

相关推荐
王老师青少年编程2 小时前
信奥赛C++提高组csp-s之组合数学专题课:卡特兰数
c++·组合数学·卡特兰数·csp·信奥赛·csp-s·提高组
YJlio2 小时前
《Windows 11 从入门到精通》读书笔记 1.4.9:全新的微软应用商店——“库 + 多设备同步”把它从鸡肋变成刚需入口
c语言·网络·python·数码相机·microsoft·ios·iphone
智者知已应修善业2 小时前
【C++非递归剪枝问题凑钱方案数】2024-7-18
c语言·c++·经验分享·笔记·算法·剪枝
BigLeo2 小时前
c++中,声明(Declaration)与定义(Definition)有什么不同?
c++
YJlio2 小时前
《Windows 11 从入门到精通》读书笔记 1.4.10:集成的微软 Teams——办公与社交的无缝衔接
c语言·网络·python·数码相机·ios·django·iphone
星辰徐哥2 小时前
C语言Web开发:CGI、FastCGI、Nginx深度解析
c语言·前端·nginx
Yolo_TvT2 小时前
C++:缺省参数
开发语言·c++·算法
承渊政道2 小时前
【优选算法】(实战领略前缀和的真谛)
开发语言·数据结构·c++·笔记·学习·算法
xiaoliuliu123452 小时前
Dev C++ 5.11开发编辑器 安装教程:详细步骤+自定义安装路径(附简体中文设置)
开发语言·c++