实现c++对Libcurl的post调用一些爬坑记录

9 篇文章 0 订阅

@[TOC] 目录

# 摘要

本文实现c++使用libcurl开源库,对websocket服务的客服端post请求遇到的一些坑的反思记录。

libcurl版本:curl-7.76.0.zip

libcurl下载、编译、函数说明、接口调用可以参照如下网址,不做过多的画蛇添足。

https://www.cnblogs.com/heluan/p/10177475.html

备注:可以参考如下链接方式,搭建postman的mock server服务端测试post请求。

https://blog.csdn.net/hbiao68/article/details/102757845

遇到的问题列表如下:

1.post发送服务端未接收到数据

2.多字节工程与Http要求UTF_8编码格式冲突

3.无法接受post返回数据

4.如何发送接受json数据,接受到的数据转JSON失败的坑

 

# 1.post发送服务端未接收到数据

原因:未指定发送数据长度

解决方案:设置curl_easy_setopt函数的CURLOPT_POSTFIELDS、CURLOPT_POSTFIELDSIZE字段的值。

已知std::string requestUTF8("post send data");

字段说明
字段名意义参数案例
CURLOPT_POSTFIELDS发送的数据字段requestUTF8.data()
CURLOPT_POSTFIELDSIZE发送数据的长度requestUTF8.size()

 

 

 

 

代码示例

curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestUTF8.data());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, requestUTF8.size());

 

#  2.多字节工程与Http要求UTF_8编码格式冲突

原因:VC工程为Use Multi-Byte Character Set多字节,而Http发送接受编码格式为UTF_8

解决方案

将ANSCII格式的string类型转成UTF_8格式的string。

std::string -->std::wstring(UNICODE)-->UTF_8

前置条件:Windows API函数需要引入Windows头文件  #include <Windows.h>

inline  std::wstring AsciiToUnicode(const std::string& str)
{
	// 预算-缓冲区中宽字节的长度  
	int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
	// 给指向缓冲区的指针变量分配内存  
	wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
	// 开始向缓冲区转换字节  
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
	std::wstring ret_str = pUnicode;
	free(pUnicode);
	return ret_str;
}

inline  std::string UnicodeToUtf8(const std::wstring& wstr)
{
	// 预算-缓冲区中多字节的长度  
	int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
	// 给指向缓冲区的指针变量分配内存  
	char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
	// 开始向缓冲区转换字节  
	WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
	std::string ret_str = pAssii;
	free(pAssii);
	return ret_str;
}


inline  std::string AsciiToUtf8(const std::string& str)
{
	return UnicodeToUtf8(AsciiToUnicode(str));
}

 

#  3.无法接受post返回数据

原因:1.未设置返回接受数据和返回写入回调函数

           2.写入回调函数有问题

解决方案:

        第一点问题可以设置curl_easy_setopt函数的CURLOPT_WRITEFUNCTION、CURLOPT_WRITEDATA字段的值。

已知std::ostringstream writedata;

字段说明
字段名意义参数案例
CURLOPT_WRITEFUNCTION设置返回数据写入的回调函数write_data
CURLOPT_WRITEDATA设置返回数据写入的变量writedata

 

 

 

 

write_data为函数指针,可参照如下代码,建议最好是以字符流操作。

尝试过返回string*和char*指针存在崩溃或无返回情况。

ostringstream记得加头文件#include<sstream>

size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{

	std::string html_data(reinterpret_cast<const char*>(buffer), size * nmemb);
	*(reinterpret_cast<std::ostringstream*>(userp)) << html_data;

	return size * nmemb;
}

调用案例:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writedata);

# 4.如何发送接受json数据,接受到的数据转JSON失败的坑

原因:接受数据按照字节串流不满足JsonCPP库的parse函数调用

解决方案:需要将字节流转成UTF8字符数组

具体是ostringstream.str()得到字节流(byte类型)--》UNICODE--》UTF8格式字节流

字符编码笔记:ASCII,Unicode 和 UTF-8可通过如下地址学习

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

代码:已知std::string reponse;

reponse = AsciiToUtf8(writedata.str());
Json::Reader reader;
Json::Value root,body;



	
if (reader.parse(reponse.data(), body))
{

//your json data
}

完整示例代码如下:

bool doPost(int ack, const std::string &method, std::string &req, std::shared_ptr<std::string> &rep)
{

	std::string reponse = "";
	std::string request;
	request.append("{");
	request.append(req.data());
	request.append("}");
	
	//避免路径'\'理解成反转义
	for (size_t i = 0; i<request.size(); i++) {
		if (request[i] == '\\') {
			request.insert(i, std::string("\\"));
			i++;
		}
	}

	std::string requestUTF8 = AsciiToUtf8(request);

	std::string url = realUrl;
	
	
    CURL *curl = curl_easy_init();
	struct curl_slist *headers = NULL;
	std::ostringstream writedata;
	if (curl)
	{
	    
		headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
		headers = curl_slist_append(headers, "Accept: application/json");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//设置HTTP头
		
		curl_easy_setopt(curl, CURLOPT_URL, url.data());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestUTF8.data());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, requestUTF8.size());

		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writedata);

		curl_easy_setopt(curl, CURLOPT_POST, 1);
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_HEADER, 1);
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "d:/curlposttest.cookie");

			/*如果在60秒内低于30字节 / 秒,则中止*/
			/*
		curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60);
		curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 10);
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2);//连接超时,这个数值如果设置太短可能导致数据请求不到就断开了
		curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 3000);//接收数据时超时设置,如果10秒内数据未接收完,直接退出
			*/
		

		curl_easy_perform(curl);

		reponse = AsciiToUtf8(writedata.str());
		reponse = reponse.substr(reponse.find_first_of('{'));
		
		url_slist_free_all(headers);
		curl_easy_cleanup(curl);
		curl = nullptr;
		
	}
	
	rep = std::shared_ptr<std::string>(new std::string(reponse));
	return true;
}

 

附加

utf8转anscii方法源代码,使用到c++11宽窄字符转换,记得加头文件#include <codecvt> 

std::string UnicodeToAscii(const std::wstring &str)
{
	int	iTextLen = WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
	std::vector<char> vecText(iTextLen, '\0');
	::WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, &(vecText[0]), iTextLen, NULL, NULL);

	std::string strText = &(vecText[0]);

	return strText;

}

std::string UTF8ToString(const std::string &utf8Data)
{
	//先将UTF-8转换成Unicode
	std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
	std::wstring wString = conv.from_bytes(utf8Data);
	//在转换成string
	return UnicodeToAscii(wString);
}

inline  std::string Utf8ToAscii(const std::string& str)
{
	return UTF8ToString(str);
}

ANSI码字节流 ---------(AsciiToUtf8方法)-------------------------》UTF8码字节流

UTF8码字节流 ---------(Utf8ToAscii方法)-------------------------》ANSI码字节流

GBK:0xB0 0xA1;                 Unicode-16 LE:0x4A 0x55,

Unicode-16 BE:0x55 0x4A; UTF-8:0xE5 0x95 0x8A

总结:

1.写Windows工程绕不过编码格式,对于计算机只有二进制,对于上层需要码制转换。感谢c++11宽窄字符转换,省了很大的力气。(Linux默认是UTF8不存在码制问题)

2.HTTP通信数据多采用UTF8编码,工程最好设置为UNICODE;

3.libcurl功能很强大,支持多种协议是作为客户端不错开源库。

4.c++11是c++灵魂的深造,解决长期困扰的多线程、函数指针、RAII、时间库等问题。

技术选型 c++11 + libcurl + jsoncpp

求助:望大神分享c++下httplib库编译、使用案例。万分感谢!!!

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
HTTP(超文本传输协议)是一种用于传输超文本和其他资源的应用层协议。HTTP Post是一种用于将数据发送到服务器的HTTP请求方法。 在C语言中实现HTTP Post可以通过使用libcurl库来实现libcurl是一个开源的URL传输库,可以支持多种网络协议,包括HTTP。 为了使用libcurl实现HTTP Post,我们首先需要在编译环境中安装libcurl库。然后,在代码中添加libcurl头文件,并链接libcurl库以确保可以使用相关函数。 下面是一个示例代码,展示了如何使用libcurl实现HTTP Post: ```c #include <stdio.h> #include <curl/curl.h> int main(void) { CURL *curl; CURLcode res; // 初始化libcurl curl_global_init(CURL_GLOBAL_DEFAULT); // 创建一个curl句柄 curl = curl_easy_init(); if(curl) { // 设置HTTP POST请求的URL curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); // 设置HTTP POST的数据 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "data=HelloCurl"); // 执行HTTP POST请求 res = curl_easy_perform(curl); // 检查请求是否成功 if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); // 清理curl句柄 curl_easy_cleanup(curl); } // 清理libcurl curl_global_cleanup(); return 0; } ``` 在上面的代码中,首先使用curl_global_init()函数初始化libcurl库。然后,通过调用curl_easy_init()函数创建一个curl句柄。 通过调用curl_easy_setopt()函数设置相关选项,例如设置URL和POST数据。在这个例子中,我们将URL设置为"http://example.com",将POST数据设置为"data=HelloCurl"。 最后,我们执行HTTP POST请求,并通过检查返回的结果来判断是否成功执行。 在完成HTTP POST请求后,我们使用curl_easy_cleanup()函数清理curl句柄,并通过调用curl_global_cleanup()函数清理libcurl。 综上所述,以上代码示例演示了如何使用libcurl库在C语言中实现HTTP Post请求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值