curl 是一个强大的命令行工具,用于与 URL 进行数据传输,支持多种协议。以下是使用 curl 进行 GET、POST 请求和文件上传的详细参数设置和调用细节。
1. GET 请求
GET 请求用于从服务器获取数据。
示例
curl -X GET "http://example.com/api/resource?param1=value1¶m2=value2"
参数说明
-X GET:显式指定使用 GET 方法(通常可以省略,因为curl默认使用 GET)。- URL:请求的目标 URL,可以附带查询参数。
其他常用选项
-H "Authorization: Bearer <token>":添加请求头,如授权信息。-o output.txt:将响应内容写入文件。
2. POST 请求
POST 请求用于向服务器提交数据。
示例
curl -X POST "http://example.com/api/resource" -d "param1=value1¶m2=value2"
参数说明
-X POST:显式指定使用 POST 方法。-d:后面跟随数据,格式可以是key=value的形式。可以多次使用-d添加多个参数。
使用 JSON 数据
如果要发送 JSON 数据,可以使用 -H 选项设置内容类型:curl -X POST "http://example.com/api/resource" -H "Content-Type: application/json" -d '{"param1":"value1", "param2":"value2"}'
3. 上传文件
上传文件通常使用 POST 请求。curl -X POST "http://example.com/upload" -F "file=@/path/to/file.txt"
参数说明
-F:表示表单数据,后面跟随file=@/path/to/file.txt,其中@表示读取本地文件。- 可以同时上传多个文件:
curl -X POST "http://example.com/upload" -F "file1=@/path/to/file1.txt" -F "file2=@/path/to/file2.jpg"
4. 其他常用选项
-H:添加自定义请求头。-v:显示详细的请求和响应信息,便于调试。-L:跟随重定向。--data-urlencode:对数据进行 URL 编码。
5. 综合示例
以下是一个综合示例,展示如何使用 GET 和 POST 请求、上传文件以及设置请求头:
# GET 请求 curl -X GET "http://example.com/api/resource?param1=value1" # POST 请求 curl -X POST "http://example.com/api/resource" -H "Content-Type: application/json" -d '{"param1":"value1", "param2":"value2"}' # 上传文件 curl -X POST "http://example.com/upload" -F "file=@/path/to/file.txt" -H "Authorization: Bearer <token>"
6. 注意事项
- 确保 URL 正确,特别是在 POST 和文件上传的情况下。
- 对于需要认证的 API,确保传递必要的认证信息。
- 检查返回的状态码和响应内容,以确保请求成功。
通过合理使用 curl 的各种选项,可以方便地与 HTTP 服务进行交互,进行数据获取、提交和文件上传等操作。
7. 工程代码实例
- Curl初始化参数
// 这个接口里面设置的参数选项已经完全覆盖了 Get、Post、HttpPost(文件上传)操作
int HttpClient::initCurl(const HttpClientUrlArgs &urlArgs) {
auto headers = urlArgs.headers;
std::vector<std::string> ips;
if (XXX::XXX::GetInstance().GetProxyConfigInfo().m_httpDnsEnable) {
ips = XXX::XXX::GetInstance().GetIpsByHostName(urlArgs.hostName);
}
if (ips.empty()) {
m_requestUrl = XXX::SplicingUrl(urlArgs.protocol, urlArgs.hostName, urlArgs.port, urlArgs.url, urlArgs.args);
} else {
m_requestUrl = XXX::SplicingUrl(urlArgs.protocol, ips[RandomNum()%ips.size()], urlArgs.port, urlArgs.url, urlArgs.args);
headers.emplace("Host", urlArgs.hostName);
}
if (m_pCurl != nullptr) {
curl_easy_cleanup(m_pCurl);
m_pCurl = nullptr;
}
if (m_pHeadList != nullptr) {
curl_slist_free_all(m_pHeadList);
m_pHeadList = nullptr;
}
m_pCurl = curl_easy_init();
if (m_pCurl == nullptr) {
return -1;
}
curl_easy_setopt(m_pCurl, CURLOPT_URL, m_requestUrl.c_str()); // 请求地址
curl_easy_setopt(m_pCurl, CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, HttpClientOnWriteCallback); // 写回调:如Post、HttpPost
curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, this);
curl_easy_setopt(m_pCurl, CURLOPT_READFUNCTION, HttpClientOnReadCallback); // 读回调:如Get
curl_easy_setopt(m_pCurl, CURLOPT_READDATA, this);
curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 10L);
curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(m_pCurl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0L);
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, HttpClientOnProgressCallback);
curl_easy_setopt(m_pCurl, CURLOPT_FAILONERROR, 1L);
m_pHeadList = curl_slist_append(m_pHeadList, "Expect:");
if (!headers.empty()) {
for (const auto& it : headers) {
auto tmp = it.first + ": " + it.second;
m_pHeadList = curl_slist_append(m_pHeadList, tmp.c_str());
}
}
curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pHeadList);
return 0;
}
- 上传文件核心参数
int HttpClient::OnProgressCallback(double dt, double dn, double ult, double uln) {
if (m_isExit != nullptr && m_isExit()) {
return -1;
}
return 0;
}
// 读回调
size_t HttpClient::OnReadCallback(void *buffer, size_t size, size_t nmemb, void *arg){
return nmemb*size;
}
// 写回调
size_t HttpClient::OnWriteCallback(void *buffer, size_t size, size_t nmemb, void *arg) {
if (buffer != nullptr && size > 0 && nmemb > 0) {
m_result.append((char*)buffer, size*nmemb);
}
return size*nmemb;
}
// 获取必要的参数 具体看需求
void HttpClient::UpdateInfo() {
if (m_pCurl == nullptr) {
return;
}
double dnsTime = 0;
if (curl_easy_getinfo(m_pCurl, CURLINFO_NAMELOOKUP_TIME, &dnsTime) == CURLE_OK) {
m_iDnsTime = dnsTime*1000;
}
long code = 0;
if (curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &code) == CURLE_OK) {
m_iCurlCode = code;
}
char *ip = nullptr;
if ((curl_easy_getinfo(m_pCurl, CURLINFO_PRIMARY_IP, &ip) == CURLE_OK) && (ip != nullptr)) {
m_remoteIp = ip;
}
double temp = 0.0;
const unsigned int k_dwThousand = 1000;
if (curl_easy_getinfo(m_pCurl, CURLINFO_TOTAL_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwTotalTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_NAMELOOKUP_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwNameLookupTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_CONNECT_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwConnectTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_PRETRANSFER_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwPretransferTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_FILETIME, &m_interactionTime.lFileTime) == CURLE_OK) {
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_STARTTRANSFER_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwStartTransferTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_REDIRECT_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwRedirectTime = (uint32_t)(temp * k_dwThousand);
}
if (curl_easy_getinfo(m_pCurl, CURLINFO_APPCONNECT_TIME, &temp) == CURLE_OK) {
m_interactionTime.dwAppconnetTime = (uint32_t)(temp * k_dwThousand);
}
}
// Get操作
int HttpClient::GetData(std::string &result, const HttpClientUrlArgs &urlArgs) {
if (initCurl(urlArgs) != 0) {
xerror2(TSF"init curl error!");
return -1;
}
m_result.clear();
auto res = curl_easy_perform(m_pCurl);
if (res != CURLE_OK) {
xerror2(TSF"url: %_, res: %_", m_requestUrl.c_str(), res);
}
result.clear();
result = std::move(m_result);
UpdateInfo();
return res;
}
// Post操作
int HttpClient::PostData(std::string &result, const HttpClientUrlArgs &urlArgs, const std::string &content) {
result.clear();
if (initCurl(urlArgs) != 0) {
xerror2(TSF"init curl error!");
return -1;
}
curl_easy_setopt(m_pCurl, CURLOPT_POST, true);
curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, content.c_str());
m_result.clear();
auto res = curl_easy_perform(m_pCurl);
if (res != CURLE_OK) {
xerror2(TSF"url: %_, res: %_", m_requestUrl.c_str(), res);
}
result = std::move(m_result);
UpdateInfo();
return res;
}
// 上传文件操作
int HttpClient::PostBinaryData(std::string &result, const HttpClientUrlArgs &urlArgs, const std::string &filePath, const std::string &fileName) {
if (initCurl(urlArgs) != 0) {
xerror2(TSF"init curl error!");
return -1;
}
if (m_pFormpost != nullptr) {
curl_formfree(m_pFormpost);
m_pFormpost = nullptr;
}
struct curl_httppost *lastPtr = nullptr;
// 注意参数顺序, 这块踩过坑; 之前因为参数顺序问题查了好久
curl_formadd(&m_pFormpost, &lastPtr, CURLFORM_PTRNAME, "log_file", CURLFORM_FILENAME, fileName.c_str(), CURLFORM_FILE, filePath.c_str(), CURLFORM_END);
// 跟服务端定 需要什么字段, 就如下写法加什么字段
curl_formadd(&m_pFormpost, &lastPtr, CURLFORM_PTRNAME, "client_id", CURLFORM_PTRCONTENTS, XXX.c_str(), CURLFORM_END);
curl_easy_setopt(m_pCurl, CURLOPT_HTTPPOST, m_pFormpost);
m_result.clear();
auto res = curl_easy_perform(m_pCurl);
if (res != CURLE_OK) {
xerror2(TSF"curl easy perform error, url: %_, res: %_", m_requestUrl.c_str(), res);
return res;
}
// 获取WriteCallBack中的结果信息来判断这次执行是否成功以及查询出错原因
result = std::move(m_result);
UpdateInfo();
return 0;
}
- 外部调用核心参数
// 上传文件部分调用核心代码
HttpClientUrlArgs urlArgs;
...
// Content-Type格式——上传文件
urlArgs.headers["Content-Type"] = "multipart/form-data";
// Content-Type格式——Post字符串
urlArgs.headers["Content-Type"] = "text/plain"; // 一般是内存中字符串, 如日志上传
urlArgs.headers["Content-Type"] = "application/json"; // 默认的json格式
// Content-Type格式——Get操作
urlArgs.headers["Content-Type"] = 可以不指定这个字段, 走默认"application/json";
// 注意: Curl提供了客户线程退出标识检查机制(新版本废弃)
int HttpClient::OnProgressCallback(double dt, double dn, double ult, double uln) {
if (m_isExit != nullptr && m_isExit()) {
return -1;
}
return 0;
}
// 如下设置回调isExit标识当前线程是否退出
...
std::shared_ptr<HttpClient> httpClient = std::make_shared<HttpClient>(XXX::bind(&XXX::isExit, this));
...
该博客详细介绍了如何使用C++实现一个HTTP客户端,支持GET、POST和文件上传操作。通过Curl库初始化参数,设置各种HTTP请求选项,包括设置超时、SSL验证、回调函数等。同时,还展示了如何处理进度回调、读写回调以及获取请求的交互时间等信息。此外,还提供了上传文件的核心参数设置和外部调用的示例代码。

7055

被折叠的 条评论
为什么被折叠?



