版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/52200348
我们的webservice服务器端是以axis2为基础构建的,客户端提交的soap请求参数不正确或其他情况下,会抛出异常给客户端。这些异常在SOAP这一层是以Fault类型的消息呈现的,比如目前有如下异常:
DeleteImgFail // 图像文件删除失败 DuplicateReord // 数据库记录重复 ImageError // 图像读写或格式错误 NotFaceDetected // 没有检测到人脸 NotFoundBean // 没有数据库找到记录 ServiceRuntime // 服务端的运行时异常(java.lang.RuntimeException)
比如本文示例的detectFace调用的服务器端的java代码实现如下(代码中声明会抛出ImageError,ServiceRuntime异常):
/** * 参见{@link FaceAPILocal#detectFace(byte[],FRect)}<br> * @param imgData * @param detectRectangle * @return CodeInfo[] * @throws ImageError * @see FaceAPILocal#detectFace(byte[],FRect) */ public final CodeInfo[] sdk_detectFace (byte[] imgData,FRect detectRectangle) throws ImageError,ServiceRuntime{ try{ return _faceAPIInstance.detectFace(imgData,detectRectangle); }catch (RuntimeException e) { throw new ServiceRuntime(e); } }
当客户端调用webservice出现异常时,需要能获取异常类型然后根据需要做相应的处理。这就需要当soap调用失败时,不仅能输出faultstring,还要知道异常类型。
于是仔细研究了gsoap的异常处理 《SOAP Fault Processing》
下面的代码摘自gosap官网手册,是gosap的异常数据结构,根据官网的说明SOAP_ENV__Fault
中前面4个字段用于SOAP 1.1,后面5个字段用于SOAP 1.2。不论是SOAP 1.1还是SOAP 1.2都有一个类型为SOAP_ENV__Detail*
的字段。
struct SOAP_ENV__Fault { _QName faultcode; // _QName is builtin char *faultstring; char *faultactor; struct SOAP_ENV__Detail *detail; struct SOAP_ENV__Code *SOAP_ENV__Code; // MUST be a SOAP_ENV__Code struct defined below char *SOAP_ENV__Reason; char *SOAP_ENV__Node; char *SOAP_ENV__Role; struct SOAP_ENV__Detail *SOAP_ENV__Detail; // SOAP 1.2 detail field };
这是官网上SOAP_ENV__Detail
结构的说明,很简单,我推测这应该是通用版本。
struct SOAP_ENV__Detail { int __type; // The SOAP_TYPE_ of the object serialized as Fault detail void *fault; // pointer to the fault object, or NULL char *__any; // any other detail element content (stored in XML format) };
我生的代码中SOAP_ENV__Detail
实际定义如下:
/* facedbservice.h:4949 */ #ifndef WITH_NOGLOBAL #ifndef SOAP_TYPE_SOAP_ENV__Detail #define SOAP_TYPE_SOAP_ENV__Detail (215) /* SOAP_ENV__Detail: */ struct SOAP_ENV__Detail { public: /** Optional element 'ns1:FaceDbServiceDeleteImgFail' of XSD type 'ns1:FaceDbServiceDeleteImgFail' */ _ns1__FaceDbServiceDeleteImgFail *ns1__FaceDbServiceDeleteImgFail; /** Optional element 'ns1:FaceDbServiceDuplicateReord' of XSD type 'ns1:FaceDbServiceDuplicateReord' */ _ns1__FaceDbServiceDuplicateReord *ns1__FaceDbServiceDuplicateReord; /** Optional element 'ns1:FaceDbServiceImageError' of XSD type 'ns1:FaceDbServiceImageError' */ _ns1__FaceDbServiceImageError *ns1__FaceDbServiceImageError; /** Optional element 'ns1:FaceDbServiceNotFaceDetected' of XSD type 'ns1:FaceDbServiceNotFaceDetected' */ _ns1__FaceDbServiceNotFaceDetected *ns1__FaceDbServiceNotFaceDetected; /** Optional element 'ns1:FaceDbServiceNotFoundBean' of XSD type 'ns1:FaceDbServiceNotFoundBean' */ _ns1__FaceDbServiceNotFoundBean *ns1__FaceDbServiceNotFoundBean; /** Optional element 'ns1:FaceDbServiceServiceRuntime' of XSD type 'ns1:FaceDbServiceServiceRuntime' */ _ns1__FaceDbServiceServiceRuntime *ns1__FaceDbServiceServiceRuntime; /** Any type of element 'fault' assigned to fault with its SOAP_TYPE_T assigned to __type */ /** Do not create a cyclic data structure throught this member unless SOAP encoding or SOAP_XML_GRAPH are used for id-ref serialization */ int __type; void *fault; char *__any; public: /** Return unique type id SOAP_TYPE_SOAP_ENV__Detail */ int soap_type() const { return SOAP_TYPE_SOAP_ENV__Detail; } /** Constructor with member initializations */ SOAP_ENV__Detail() { ns1__FaceDbServiceDeleteImgFail = (_ns1__FaceDbServiceDeleteImgFail *)0; ns1__FaceDbServiceDuplicateReord = (_ns1__FaceDbServiceDuplicateReord *)0; ns1__FaceDbServiceImageError = (_ns1__FaceDbServiceImageError *)0; ns1__FaceDbServiceNotFaceDetected = (_ns1__FaceDbServiceNotFaceDetected *)0; ns1__FaceDbServiceNotFoundBean = (_ns1__FaceDbServiceNotFoundBean *)0; ns1__FaceDbServiceServiceRuntime = (_ns1__FaceDbServiceServiceRuntime *)0; __type = 0; fault = NULL; __any = (char *)0; } /** Friend allocator used by soap_new_SOAP_ENV__Detail(struct soap*, int) */ friend SOAP_FMAC1 SOAP_ENV__Detail * SOAP_FMAC2 facedbservice_instantiate_SOAP_ENV__Detail(struct soap*, int, const char*, const char*, size_t*); }; #endif #endif
对比官网手册上的代码就发现实际的SOAP_ENV__Detail
结构中多了几个成员变量:
ns1__FaceDbServiceDeleteImgFail ns1__FaceDbServiceDuplicateReord ns1__FaceDbServiceImageError ns1__FaceDbServiceNotFaceDetected ns1__FaceDbServiceNotFoundBean ns1__FaceDbServiceServiceRuntime
而这多出来的成员变量正好与前面我的服务器端抛出的异常对应。
当我尝试让服务器端抛出ServerRuntime异常时,SOAP_ENV__Detail
结构中对应的ns1__FaceDbServiceServiceRuntime成员变量被赋值了一个异常类型对象,其他变量都为null,这正是我要的结果.
搞清楚原理,就可以对服务器端异常类型进行判断和处理,下面是代码示例. test_gsoap.cpp
#include <sstream> #include "FaceDbServiceSoap11Binding.nsmap" #include "file_utilits.h" #include "stdlib.h" // 根据soap.version判断SOAP1.1或SOAP1.2版本,返回不同的字段 SOAP_ENV__Detail* getFaultDetail(soap &soap) { return soap.version == 2 ? soap.fault->SOAP_ENV__Detail : soap.fault->detail; } int main(int argc, char * argv[]) { soap soap; // 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(); // 原本这里应该将设置b为图像数据,但这里故意删除,不给imgData赋值(为null),以便让服务器抛出ServerRuntime异常。 //param.imgData = &b; soap_call___ns1__sdk_USCOREdetectFace(&soap,"http://gdface.wicp.net:15865/axis2/services/FaceDbService",nullptr, ¶m,ret); if (soap.error!= SOAP_OK) { soap_fault(&soap); // 获取SOAP_ENV__Detail对象指针 auto detail = getFaultDetail(soap); if (detail) { // 根据每个异常对应的字段是否为null判断异常类型做相应的处理 if (detail->ns1__FaceDbServiceDeleteImgFail) { cout << "FaceDbServiceDeleteImgFail:"<< *soap_faultdetail(&soap) << endl; }else if (detail->ns1__FaceDbServiceDuplicateReord) { cout << *detail->ns1__FaceDbServiceDuplicateReord->DuplicateReord->message << endl; }else if (detail->ns1__FaceDbServiceImageError) { cout << "FaceDbServiceImageError:"<< *soap_faultdetail(&soap) << endl; }else if (detail->ns1__FaceDbServiceNotFaceDetected) { cout << "FaceDbServiceNotFaceDetected:"<< *soap_faultdetail(&soap) << endl; }else if (detail->ns1__FaceDbServiceNotFoundBean) { cout << "FaceDbServiceNotFoundBean:"<< *soap_faultdetail(&soap) << endl; }else if (detail->ns1__FaceDbServiceServiceRuntime) { // 输出服务器端的堆栈信息 cout << *detail->ns1__FaceDbServiceServiceRuntime->ServiceRuntime->serverStackTraceMessage << endl; }else { // 如果非服务器端代码抛出异常则调用soap_faultdetail显示错误信息。 cout << *soap_faultdetail(&soap) << std::endl; } } }else { if(ret.return_.size()) for (auto code : ret.return_) { std::printf("face rect = (%d,%d,%d,%d)\n", *(code->pos->left), *(code->pos->top), *(code->pos->width), *(code->pos->height)); } else cout << "NotFaceDetected" << endl; } soap_done(&soap); }
如下图,输出了服务器端的堆栈信息
注意:
如果使用这种方法判断异常类型,在代码生成的时候,就不能用-qname指定C++namespace
生成代码的脚本如下:
wsdl2h -o facedbservice.h http://gdface.wicp.net:15865/axis2/services/FaceDbService?wsdl soapcpp2 -C -L -x -qfacedbservice -IJ:\gsoap-2.8\gsoap\import facedbservice.h -C指定只生成client端代码 -q参数指定生成代码的文件前缀
<prefix>
,如果不指定默认前缀为soap -L指定不生成<prefix>
ClientLib.cpp文件
然后生成如下文件:
将.cpp文件和$GSOAP\gsoap\stdsoap2.cpp加入工程,就可以编译了。
参考资料 《SOAP Fault Processing》 http://www.genivia.com/doc/soapdoc2.html#tth_sEc12
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句