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

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

c++通过gsop调用基于https的webservice接口总结_第3张图片

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

wsdl2h.exe -o head.h http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL

c++通过gsop调用基于https的webservice接口总结_第4张图片

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

c++通过gsop调用基于https的webservice接口总结_第5张图片

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

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

soap_set_mode(&m_soap, SOAP_C_UTFSTRING);

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

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

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

第二步:生成可调用API

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

soapcpp2.exe -C -x -I ..\..\import head.h

c++通过gsop调用基于https的webservice接口总结_第6张图片  

其中-C是只生成客户端代码。-x表示不生成xml(我们只需要c++代码)-I 是指定import目录。
执行成功之后,当前目录下多了一些文件:

c++通过gsop调用基于https的webservice接口总结_第7张图片

 第三步:导入到项目
将上面图片中红色框中的文件添加到你的项目中。另外还有需要添加两个文件。gsoap根目录下的stdsoap2.h和stdsoap2.cpp也需要添加到项目中。
对添加进去的3个cpp文件右击->属性->所有配置->c/c+±>预编译头,选择不使用预编译头。如下如所示。
c++通过gsop调用基于https的webservice接口总结_第8张图片

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

第四步:编写代码

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

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

#include "WeatherWebServiceSoap.nsmap"
#include "soap.h"

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

c++通过gsop调用基于https的webservice接口总结_第9张图片
在soapClient.cpp中可以看到服务的所有接口。函数名是soap_call __ns1_XXX形式。
首先创建soap对象并初始化:

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字符串中双引号需要转义。

char* _reqXml = ".....";
char* _Return;
soap_call_ns1__XXX(&m_soap, NULL, NULL, G2U(_reqXml), _Return);
string ret = U2G(_Return);

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

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)后面添加如下代码:

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++通过gsop调用基于https的webservice接口总结_第10张图片

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

c++通过gsop调用基于https的webservice接口总结_第11张图片

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

c++通过gsop调用基于https的webservice接口总结_第12张图片

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

原因

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

c++通过gsop调用基于https的webservice接口总结_第13张图片

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

c++通过gsop调用基于https的webservice接口总结_第14张图片

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

c++通过gsop调用基于https的webservice接口总结_第15张图片

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

c++通过gsop调用基于https的webservice接口总结_第16张图片

文件结构

c++通过gsop调用基于https的webservice接口总结_第17张图片

 注意:

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

c++通过gsop调用基于https的webservice接口总结_第18张图片

 解决方法:

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

c++通过gsop调用基于https的webservice接口总结_第19张图片

 以下是gsoap+opensll工具

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

你可能感兴趣的:(c++,开发语言,https,http,网络协议)