前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >gsoap入门:解决axis2服务器返回错误

gsoap入门:解决axis2服务器返回错误

作者头像
10km
发布2019-05-25 22:16:55
1.5K0
发布2019-05-25 22:16:55
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433623

我们的项目中webservice服务器已经搭建好,基于用axis2提供名为FaceDbService的人脸识别服务。现在的任务是用gosap开发C++版本的客户端,所以最近在尝试用gsoap生成的c++代码来调用webservice.

关于生成gsoap C++客户端代码及编译,参见我的前一篇博客《gsoap入门:C/C++代码生成及编译》

测试代码

下面是测试代码

代码语言:javascript
复制
#include <sstream>
#include "FaceDbServiceSoap11Binding.nsmap"
#include "file_utilits.h"
#include "stdlib.h"
#include "plugin.h"
using namespace facedbservice;
int main(int argc, char * argv[]) {
    struct soap soap;
    // 对象初始化
    soap_init(&soap);
    // 注册plugin插件,用于显示request/response xml文本用于调试
    soap_register_plugin(&soap, plugin);
    // RPC调用参数对象
    _ns1__sdk_USCOREdetectFace param;
    // RPC返回对象
    _ns1__sdk_USCOREdetectFaceResponse ret;
    // 加载一张图像数据到内存(字节数组std::vector<uint8_t>)
    auto img_file= gdface::load_binary_file("d:\\tmp\\he049.jpg");
    // 将字节数组转为xsd__base64Binary对象,并设置为imgData参数
    xsd__base64Binary b;
    b.soap = &soap;
    b.__ptr = img_file.data();
    b.__size = img_file.size();
    param.imgData = &b;
    // 执行soap调用detectFace
    soap_call___ns1__sdk_USCOREdetectFace(&soap,"http://gdface.wicp.net:15865/axis2/services/FaceDbService",nullptr, &param,ret);
    // 检查错误
    if (soap.error!= SOAP_OK) {
        // 显示错误信息
        soap_stream_fault(&soap, std::cerr);
    }else {
        // 调用成功则输出返回的数据
        for (auto code : ret.return_) {
            std::printf("soap err,errcode = (%d,%d,%d,%d)\n", *(code->pos->left), *(code->pos->top), *(code->pos->width), *(code->pos->height));
        }
    }
    soap_done(&soap);
}

错误信息

程序执行时出错了:

代码语言:javascript
复制
/////////plugin插件输出的 request xml///////////////////////////////////
POST /axis2/services/FaceDbService HTTP/1.1
Host: 192.168.1.18:8080
User-Agent: gSOAP/2.8
Content-Type: text/xml; charset=utf-8
Content-Length: 8583
Connection: close
SOAPAction: "urn:sdk_detectFace"

<?xml version="1.0" encoding="UTF-8"?>
<ns:sdk_detectFace><ns:imgData>
//...图像数据
</ns:imgData></ns:sdk_detectFace>


HTTP/1.1 500 Int
ernal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Sat, 13 Aug 2016 02:55:08 GMT
Connection: close
/////////plugin插件输出的 response xml///////////////////////////////////

205
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://sc
hemas.xmlsoap.org/soap/envelope/"><soapenv:Header xmlns:wsa="http://www.w3.org/2
005/08/addressing"><wsa:Action>http://www.w3.org/2005/08/addressing/soap/fault</
wsa:Action></soapenv:Header><soapenv:Body><soapenv:Fault><faultcode></faultcode>
<faultstring>com.ctc.wstx.exc.WstxParsingException: Undeclared namespace prefix
"ns1"
 at [row,col {unknown-source}]: [2,19]</faultstring><detail /></soapenv:Fault></
soapenv:Body></soapenv:Envelope>

///////// 上面代码中soap_stream_fault()输出///////
Error 500 fault at source[no subcode]
"Error 500: HTTP 500 Internal Server Error"
Detail: [no detail]

原因分析

总是返回Undeclared namespace prefix "ns"

仔细查看request xml输出发现这个xml居然没有SOAP-ENV:Envelopetag,这不是个标准的SOAP格式啊。

试了各种 关键字在google/baidu上搜索,最后用”gsoap not SOAP-ENV:Envelope”用google在stackoverflow上找到一个类似的情况《Breaking changes in gsoap (updating version from 2.8.8 to 2.8.16)》

其中一个答案,给了我提醒 :

貌似是因为soap.namespaces变量为NULL造成的,再运行程序证实了这个猜测,soap.namespaces果然为NULL;

于是尝试在soap对象创建后,添加如下代码,问题解决。

代码语言:javascript
复制
if(!soap->namespaces)
    soap->namespaces=namespaces;
    // namespaces变量定义在#include "FaceDbServiceSoap11Binding.nsmap"

解决方案

虽然这样解决了问题,但还是不知道为什么呀,网上其他的教程中没有提到要手工设置soap.namespaces变量呀

于是想到跟踪soap对象的代码,看看namespaces变量是怎么被初始化的。找到了这里(soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode)函数中),看到这里瞬间明白了。:

因为我在用gsoapcpp2生成gosap C++客户端代码的时候使用了-DWITH_NONAMESPACES编译stdsoap2.cpp文件,所以这里初始化soap对象时就将namespaces指针赋值为NULL。

再进一步研究gsoap的手册关于编译参数的控制参见《9.11 Library Build Flags》,找到WITH_NONAMESPACES的说明(下图红框部分)

这里说明,如果使用了-DWITH_NONAMESPACES定义,就必须显式的使用soap_set_namespaces为soap对象指定namespace。

到此,问题基本算是搞清楚了,导致soap请求数据格式错误的直接原因是soap初始化时没有指定namespace

从上面的分析来看,解决这个问题,有两个方案:

解决方案1

去掉编译**stdsoap2.cpp**文件设置的**-DWITH_NONAMESPACES**宏定义

这个方法最简单,但在multi-client and multi-server builds模式下并不适合,因为这种模式下必须使用-DWITH_NONAMESPACES宏定义,参见《9.1 soapcpp2 Options》

解决方案2

在soap对象初始化后用**soap_set_namespaces**函数为soap对象指定namespace。

这个方法也不复杂,只是添加一行代码,前面的测试代码修改如下:

代码语言:javascript
复制
#include <sstream>
#include "FaceDbServiceSoap11Binding.nsmap"
#include "file_utilits.h"
#include "stdlib.h"
#include "plugin.h"
using namespace facedbservice;
int main(int argc, char * argv[]) {
    soap soap;
    // 对象初始化
    // soap_init(&soap);//C++下不需要,因为soap的构造函数已经执行过soap_init
    // 设置namespaces
    // namespaces变量定义在#include "FaceDbServiceSoap11Binding.nsmap"      
    soap_set_namespaces(&soap, namespaces);

    // 下面省略的代码与以前相同
    .....
    //soap_done(&soap);//C++下不需要,因为soap的析构函数会执行soap_done
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年08月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 测试代码
  • 错误信息
  • 原因分析
  • 解决方案
    • 解决方案1
      • 解决方案2
      相关产品与服务
      人脸识别
      腾讯云神图·人脸识别(Face Recognition)基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、比对、搜索、验证、五官定位、活体检测等多种功能,为开发者和企业提供高性能高可用的人脸识别服务。 可应用于在线娱乐、在线身份认证等多种应用场景,充分满足各行业客户的人脸属性识别及用户身份确认等需求。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档