c++通过gsop调用基于https的webservice接口总结

ww哦步骤:

第一步:生成头文件

webservice接口一般会有一个对外接口文档。比如:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL

问号后面的参数表示WSDL文档,是一个XML文档,看不懂配置没关系,接下来我们要通过这个文档生成c++头文件。

(1) 下载gsoap工具

下载连接:gSOAP Toolkit download | SourceForge.net

下载完成之后解压,进入gsoap\bin\win32目录下,该目录下有两个文件wsdl2h.exe和soapcpp2.exe。wsdl2h.exe用来生成头文件。光生成头文件是不够的,这个时候要用soapcpp2.exe来生成对应的c++文件结构,可以用于项目中调用(第二步介绍)。先来看看怎么生成头文件。

在gsoap\bin\win32目录下打开cmd命令。输入:

javascript 复制代码
wsdl2h.exe -o head.h http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL

执行完成之后可以看到当前目录下多了一个head.h的头文件。可以打开看看,里面都是一些接口函数。

注意:由webservice在传输过程中默认使用UTF-8编码,当然gsoap在生成头文件的时候默认也是窄字符。比如string或者char*。此时如果再调用过程中参数有中文就会乱码。解决方案有两个。

方法一:在后面调用的时候在代码中加一句(具体加在哪里后面介绍):

javascript 复制代码
soap_set_mode(&m_soap, SOAP_C_UTFSTRING);

方法二:由于默认使用根目录下的typemap.dat进行编译成窄字符。此时我们不适用它,而是在当前目录下新建一个mytypemap.dat。内容如下:xsd__string = | std::wstring | wchar_t* 。然后重新执行cmd命令。

javascript 复制代码
wdsl2h.exe -o head.h -t mytypemap.dat http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL

重新生成之后可以发现head.h中字符串类型都变成了wchar_t * 或者wstring类型。

第二步:生成可调用API

在当前目录下执行cmd命令:

javascript 复制代码
soapcpp2.exe -C -x -I ..\..\import head.h

其中-C是只生成客户端代码。-x表示不生成xml(我们只需要c++代码)-I 是指定import目录。

执行成功之后,当前目录下多了一些文件:

第三步:导入到项目

将上面图片中红色框中的文件添加到你的项目中。另外还有需要添加两个文件。gsoap根目录下的stdsoap2.h和stdsoap2.cpp也需要添加到项目中。

对添加进去的3个cpp文件右击->属性->所有配置->c/c+±>预编译头,选择不使用预编译头。如下如所示。

配置完成之后,就可以开始写代码了。

第四步:编写代码

新建一个基于MFC应用程序工程,名称为:soapTest

新建一个soapTestDlg.cpp,引入头文件

javascript 复制代码
#include "WeatherWebServiceSoap.nsmap"
#include "soap.h"

我在项目中引用这两个头文件的时候,编译疯狂报错。仔细检查看了下,全是冲定义,原因是头文件 WeatherWebServiceSoap.nsmap中命名空间和项目中原有的socket库冲突了,解决方法是将#include "WeatherWebServiceSoap.nsmap"写到最前面,如果使用了预编译头,最好写在 stdafx.h文件中。头文件引入之后,再次编译,不报错了。如果不添加预编译头,则需要设置soapC.cpp、soapClientLib.cpp、soapClient.cpp、stdsoap2.cpp为不使用预编译头。

在soapClient.cpp中可以看到服务的所有接口。函数名是soap_call __ns1_XXX形式。

首先创建soap对象并初始化:

javascript 复制代码
struct soap m_soap;
//SOAP初始化
soap_init(&m_soap);
soap_set_mode(&m_oSoap, SOAP_C_UTFSTRING);

其中soap_set_mode(&m_oSoap, SOAP_C_UTFSTRING);正是一开始说的为了适配中文字符。如果一开始使用了wstring或者wchar_t * 则可以忽略。然后定义reqXml字符串,调用接口函数。xml字符串中双引号需要转义。

javascript 复制代码
char* _reqXml = "<root>.....</root>";
char* _Return;
soap_call_ns1__XXX(&m_soap, NULL, NULL, G2U(_reqXml), _Return);
string ret = U2G(_Return);

由于上面代码中使用的是窄字符作为参数,即char *,需要转换成UTF-8格式。具体函数如下:

javascript 复制代码
char* U2G(const char* utf8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr) delete[] wstr;
	return str;
}

char* G2U(const char* gb2312)
{
	int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr) delete[] wstr;
	return str;
}

此时编译应该可以通过了。但是,现实是残酷的。返回的_Return值为NULL,说明出错了。我的地址是https的,如果,我直接用http请求的话会返回301,查找资料说301表示重定向,意思是这里不能像浏览器那样地址栏输入http,浏览器会帮你重定向到https。此时还是得改成https。再次编译。 额~还是报错。。。错误码可以在调试期间,查看m_soap结构体中error字段的值,如果一直是0,说明没问题。具体错误代码可以上网查一下。

改成https再调试可以看到m_soap->error的值是30,查看文档,发现30代表没有进行SSL安全认证。好吧~

在soap_init(&m_soap)后面添加如下代码:

javascript 复制代码
soap_ssl_init();
if (soap_ssl_server_context(&m_soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) {
	soap_print_fault(&m_soap, stderr);
	exit(-1);
}

其中soap_ssl_server_context参数中如果有SSL证书,和密码就填进去。没有全NULL就完事儿。

再次编译,还是无法通过~检查代码,发现在stdsoap2.h头文件中WITH_OPENSSL没有定义。下面是灰色的。

解决方法:右击项目属性->C/C+±>预处理器->预处理器定义中添加WITH_OPENSSL

添加之后,发现灰色没有了

编译之后再次报错,错误信息是soap_ssl_server_context函数无法解析的外部符号。

原因

该函数的实现没有定义。忘记引入openssl库了。下载地址:https://slproweb.com/products/Win32OpenSSL.html

下载完成,安装,安装完成目录。

接着在vs中右击项目->属性->配置属性->VC++目录中包含目录和库目录添加进去,如下图。

在vs中右击项目->属性->配置属性->链接库->输入->附加依赖库项中把libcrypto.lib和libssl.lib添加进去,如下图

文件结构

注意:

如果报xx已经在 soapClient.obj 中定义的错误,如下图

解决方法:

把soapClientLib.cpp的全部注释掉,再次编译即可

以下是gsoap+opensll工具

https://download.csdn.net/download/my_angle2016/88220982

相关推荐
速盾cdn2 小时前
速盾:CDN是否支持屏蔽IP?
网络·网络协议·tcp/ip
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神6 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
机器视觉知识推荐、就业指导6 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++