[12,13].gSOAP 错误和标头处理

12  SOAP Fault Processing

A predeclared standard SOAP Fault data structure is generated by the gSOAP soapcpp2 tool for exchanging exception messages. The built-in struct SOAP_ENV__Fault data structure is defined as:

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
}; struct SOAP_ENV__Code
{
   _QName SOAP_ENV__Value;
   struct SOAP_ENV__Code *SOAP_ENV__Subcode; };
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)
};


The first four fields in SOAP_ENV__Fault are SOAP 1.1 specific. The last five fields are SOAP 1.2 specific. You can redefine these structures in the header file. For example, you can use a class for the SOAP_ENV__Fault and add methods for convenience. The data structure content can be changed to the need of an application, but this is generally not necessary because the application-specific SOAP Fault details can be serialized via the __type and fault fields in the SOAP_ENV__Detail field, see Section 11.9 on the serialization of data refered to by __type and fault. The __type field allows application data to be serialized as part of the SOAP Fault. The application data SHOULD be defined as XML elements, which requires you to declare the type names with a leading underscore to ensure that the types are compatible with XML elements and not just simpleTypes and complexTypes. When the skeleton of a service operation returns an error (see Section 10.2), then soap.fault contains the SOAP Fault data at the receiving side (client). Server-side faults are raised with soap_sender_fault or soap_receiver_fault. The soap_sender_fault call should be used to inform that the sender is at fault and the sender (client) should not resend the request. The soap_receiver_fault call should be used to indicate a temporary server-side problem, so a sender (client) can resend the request later. For example:

int ns1__myMethod(struct soap *soap, ...)
{
   ...
   return soap_receiver_fault(soap, "Resource temporarily unavailable", NULL); // return fault to sender
}


In the example, the SOAP Fault details were empty (NULL). You may pass an XML fragment, which will be literally included in the SOAP Fault message. For WS-I Basic Profile compliance, you must pass an XML string with one or more namespace qualified elements, such as:

return soap_receiver_fault(soap, "Resource temporarily unavailable", " < errorcode xmlns='http://tempuri.org' > 123 < /errorcode > < errorinfo xmlns='http://tempuri.org' > abc < /errorinfo > ");


When a service operation must raise an exception with application SOAP Fault details, it does so by assigning the soap.fault field of the current reference to the runtime context with appropriate data associated with the exception and by returning the error SOAP_FAULT. For example:

   soap_receiver_fault(soap, "Stack dump", NULL);
   if (soap->version == 2) // SOAP 1.2 is used
   {
      soap->fault->SOAP_ENV__Detail = (struct SOAP_ENV__Detail*)soap_malloc(soap, sizeof(struct SOAP_ENV__Detail);
      soap->fault->SOAP_ENV__Detail->__type = SOAP_TYPE_ns1__myStackDataType; // stack type
      soap->fault->SOAP_ENV__Detail->fault = sp; // point to stack
      soap->fault->SOAP_ENV__Detail->__any = NULL; // no other XML data
   }
   else 
   {
      soap->fault->detail = (struct SOAP_ENV__Detail*)soap_malloc(soap, sizeof(struct SOAP_ENV__Detail);
      soap->fault->detail->__type = SOAP_TYPE_ns1__myStackDataType; // stack type
      soap->fault->detail->fault = sp; // point to stack
      soap->fault->detail->__any = NULL; // no other XML data
   }
   return SOAP_FAULT; // return from service operation call


When soap_receiver_fault allocates a fault struct, this data is removed with the soap_end call (or soap_dealloc). Note that the soap_receiver_fault function is called to allocate the fault struct and set the fault string and detail fields, i.e. soap_receiver_fault(soap, "Stack dump", NULL). The advantage is that this is independent of SOAP 1.1 and SOAP 1.2. However, setting the custom detail fields requires inspecting the SOAP version used, using the soap->version attribute which is 1 for SOAP 1.1 and 2 for SOAP 1.2. Each service operation implementation in a service application can return a SOAP Fault upon an exception by returning an error code, see Section 7.2.1 for details and an example. In addition, a SOAP Fault can be returned by a service application through calling the soap_send_fault function. This is useful in case the initialization of the application fails, as illustrated in the example below:

int main()
{
   struct soap soap;
   soap_init(&soap);
   some initialization code
   if (initialization failed)
   {
      soap.error = soap_receiver_fault(&soap, "Init failed", NULL); // set the error condition (SOAP_FAULT)
      soap_send_fault(&soap); // Send SOAP Fault to client
      return 0; // Terminate
   }
}

 

13  SOAP Header Processing

A predeclared standard SOAP Header data structure is generated by the gSOAP soapcpp2 tool for exchanging SOAP messages with SOAP Headers. This predeclared data structure is:

struct SOAP_ENV__Header { };


which declares and empty header (some C and C++ compilers don't accept empty structs, use compile flag -DWITH_NOEMPTYSTRUCT to avoid these errors). To adapt the data structure to a specific need for SOAP Header processing, a new struct SOAP_ENV__Header can be added to the header file input to the gSOAP compiler. A class for the SOAP Header data structure can be used instead of a struct. For example, the following header can be used for transaction control:

struct SOAP_ENV__Header
{ char *t__transaction;
};


with client-side code:

   struct soap soap;
   soap_init(&soap);
...
soap.header = NULL; // do not use a SOAP Header for the request (as set with soap_init)
soap.actor = NULL; // do not use an actor (receiver is actor)
soap_call_method(&soap, ...);
if (soap.header) // a SOAP Header was received
   cout << soap.header->t__transaction;
// Can reset, modify, or set soap.header here before next call
soap_call_method(&soap, ...); // reuse the SOAP Header of the service response for the request
...


The SOAP Web service response can include a SOAP Header with a transaction number that the client is supposed to use for the next service operation invocation to the service. Therefore, the next request includes a transaction number:

...
<SOAP-ENV:Envelope ...>
<SOAP-ENV:Header>
<transaction xmlns="..." xsi:type="int">12345</transaction>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


This is just an example and the transaction control is not a feature of SOAP but can be added on by the application layer to implement stateful transactions between clients and services. At the client side, the soap.actor attribute can be set to indicate the recipient of the header (the SOAP SOAP-ENV:actor attribute). A Web service can read and set the SOAP Header as follows:

int main()
{
   struct soap soap;
   soap.actor = NULL; // use this to accept all headers (default)
   soap.actor = "http://some/actor"; // accept headers destined for "http://some/actor" only
   soap_serve(&soap);
}
...
int method(struct soap *soap, ...)
{
   if (soap->header) // a Header was received
      ... = soap->header->t__transaction;
   else 
      soap->header = soap_malloc(sizeof(struct SOAP_ENV__Header)); // alloc new header
...       soap->header->t__transaction = ...;
   return SOAP_OK;
}


See Section 19.2 on how to generate WSDL with the proper method-to-header-part bindings. The SOAP-ENV:mustUnderstand attribute indicates the requirement that the recipient of the SOAP Header (who must correspond to the SOAP-ENV:actor attribute when present or when the attribute has the value SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next") MUST handle the Header part that carries the attribute. gSOAP handles this automatically on the background. However, an application still needs to inspect the header part's value and handle it appropriately. If a service operation in a Web service is not able to do this, it should return SOAP_MUSTUNDERSTAND to indicate this failure. The syntax for the header file input to the gSOAP soapcpp2 compiler is extended with a special storage qualifier mustUnderstand. This qualifier can be used in the SOAP Header declaration to indicate which parts should carry a SOAP-ENV:mustUnderstand="1" attribute. For example:

struct SOAP_ENV__Header
{
   char *t__transaction;
   mustUnderstand char *t__authentication;
};


When both fields are set and soap.actor="http://some/actor" then the message contains:

<SOAP-ENV:Envelope ...>
<SOAP-ENV:Header>
<transaction xmlns="...">5</transaction>
<authentication xmlns="..."
   SOAP-ENV:actor="http://some/actor" SOAP-ENV:mustUnderstand="1">XX
</authentication>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

转载于:https://www.cnblogs.com/Arrays/archive/2013/06/11/3131888.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值