使用C++和libcurl库实现HTTP请求(GET、POST、文件上传)
在现代软件开发中,与外部API服务进行通信已成为常见需求。本文将展示如何使用C++和libcurl
库实现基本的HTTP请求,包括GET请求、POST请求(带JSON数据)以及包含文件上传的POST请求。
准备工作
首先,需要确保已安装libcurl
库,并正确链接到项目中。如果还没有安装libcurl
,可以在libcurl官网找到安装方法。使用CMake构建项目时,可以在CMakeLists.txt
中指定库路径,确保CURL能够找到:
# set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/libcurl/share/curl") # 替换为 CURL 安装的实际路径
find_package(CURL REQUIRED)
target_link_libraries(your_project_name PRIVATE CURL::libcurl)
基本结构
代码的核心是三个函数,分别用于GET请求、带JSON的POST请求和包含文件上传的POST请求。每个函数使用了libcurl
的不同配置来处理具体需求。
代码结构和功能实现
1. req_reply
:处理请求响应的函数
这个函数是libcurl
的回调函数,用于处理从服务器返回的数据,将数据写入到指定的字符串流中。
size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream) {
string *str = (string *) stream;
(*str).append((char *) ptr, size * nmemb);
return size * nmemb;
}
2. GET 请求
GET请求是最常用的请求类型,用于从服务器获取资源。curl_get_req
函数实现了GET请求,通过curl_easy_setopt
函数来设置URL和请求参数。
CURLcode curl_get_req(const std::string &url, std::string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // 忽略SSL证书验证
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return res;
}
3. 发送带JSON数据的POST请求
POST请求通常用于将数据发送到服务器,尤其是RESTful API。curl_post_json
函数可以发送包含JSON数据的POST请求,代码通过设置Content-Type
头为application/json
来指定数据类型。
CURLcode curl_post_json(const string &url, const string &jsonData, string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return res;
}
4. 发送包含JSON和文件的POST请求
在某些情况下,我们可能需要同时发送JSON数据和文件。这里用curl_mime
实现多部分表单上传。curl_mime
允许将JSON数据和文件字段一起打包并发送给服务器。
CURLcode curl_post_with_file(const string &url, const string &jsonData, const string &filePath, string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 创建 MIME 表单
curl_mime *form = curl_mime_init(curl);
// 添加 JSON 数据字段
curl_mimepart *jsonField = curl_mime_addpart(form);
curl_mime_name(jsonField, "json");
curl_mime_data(jsonField, jsonData.c_str(), CURL_ZERO_TERMINATED);
curl_mime_type(jsonField, "application/json");
// 添加文件字段
curl_mimepart *fileField = curl_mime_addpart(form);
curl_mime_name(fileField, "file");
curl_mime_filedata(fileField, filePath.c_str());
curl_mime_type(fileField, "image/png");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
res = curl_easy_perform(curl);
curl_mime_free(form);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return res;
}
测试用例
最后,我们在main
函数中展示了三个测试用例,分别是GET请求、带JSON数据的POST请求和带文件的POST请求。
#include <iostream>
#include <string>
#include "curl/curl.h"
using namespace std;
// 请求的回复处理函数
size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream) {
string *str = (string *) stream;
(*str).append((char *) ptr, size * nmemb);
return size * nmemb;
}
// HTTP GET 请求
CURLcode curl_get_req(const std::string &url, std::string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
// 设置 URL 地址
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// 设置忽略 SSL 证书验证
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// 设置回复处理函数
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
// 设置连接和响应超时时间
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl); // 执行 GET 请求
curl_easy_cleanup(curl); // 清理 curl 资源
}
return res;
}
// 发送带有 JSON 数据的 HTTP POST 请求
CURLcode curl_post_json(const string &url, const string &jsonData, string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json"); // 设置 JSON 类型头部
// headers = curl_slist_append(headers, ("appcode: " + appcode).c_str());
// headers = curl_slist_append(headers, ("User-Agent: " + agent).c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 设置 POST 请求参数
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl); // 执行 POST 请求
curl_slist_free_all(headers); // 释放头部内存
curl_easy_cleanup(curl); // 清理 curl 资源
}
return res;
}
// 发送包含 JSON 数据和文件的 POST 请求
CURLcode curl_post_with_file(const string &url, const string &jsonData, const string &filePath, string &response) {
CURL *curl = curl_easy_init();
CURLcode res;
if (curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: multipart/form-data"); // 设置多部分表单头部
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 创建 MIME 表单
curl_mime *form = curl_mime_init(curl);
// 添加 JSON 数据字段
curl_mimepart *jsonField = curl_mime_addpart(form);
curl_mime_name(jsonField, "json");
curl_mime_data(jsonField, jsonData.c_str(), CURL_ZERO_TERMINATED);
curl_mime_type(jsonField, "application/json");
// 添加文件字段
curl_mimepart *fileField = curl_mime_addpart(form);
curl_mime_name(fileField, "file");
curl_mime_filedata(fileField, filePath.c_str());
curl_mime_type(fileField, "image/png"); // 设置文件类型为 image/png
// 设置 CURL 参数
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
// 执行请求
res = curl_easy_perform(curl);
// 清理 MIME 表单和头部
curl_mime_free(form);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return res;
}
int main() {
curl_global_init(CURL_GLOBAL_ALL);
// 测试 GET 请求
string getUrlStr = "http://cn.bing.com/images/trending?form=Z9LH";
string getResponseStr;
auto res = curl_get_req(getUrlStr, getResponseStr);
if (res != CURLE_OK)
cerr << "GET 请求失败: " + string(curl_easy_strerror(res)) << endl;
else
cout << getResponseStr << endl;
// JSON POST 请求
string postUrlStr = "https://api.example.com/endpoint";
string jsonData = R"({"key1": "value1", "key2": "value2"})";
string postResponseStr;
res = curl_post_json(postUrlStr, jsonData, postResponseStr);
if (res != CURLE_OK)
cerr << "POST 请求失败: " + string(curl_easy_strerror(res)) << endl;
else
cout << postResponseStr << endl;
// JSON 和文件的 POST 请求
string postfileStr = "https://api.example.com/upload";
string filePath = "path/to/image.png"; // 指定上传的文件路径
res = curl_post_with_file(postfileStr, jsonData, filePath, postResponseStr);
if (res != CURLE_OK)
cerr << "文件 POST 请求失败: " + string(curl_easy_strerror(res)) << endl;
else
cout << "服务器响应:\n" << postResponseStr << endl;
// 清空
curl_global_cleanup();
system("pause");
return 0;
}
总结
使用libcurl
实现HTTP请求是与外部API或服务器进行通信的强大工具。本文展示了如何发送GET请求、带JSON数据的POST请求以及包含文件的POST请求,涵盖了许多实际应用中的需求。通过合理配置libcurl
选项,可以轻松实现高效且可靠的网络请求。