当soap12格式错误时请求超时

Posted

技术标签:

【中文标题】当soap12格式错误时请求超时【英文标题】:Request timeout when soap12 is malformated 【发布时间】:2021-11-22 21:15:30 【问题描述】:

我们使用 Servicestack 5.9.2 并在发送格式错误的 soap 消息时在日志文件中收到以下错误。肥皂请求超时运行。我们需要做什么才能让请求得到带有错误消息的响应?

2021-10-01 09:10:43,356 DEBUG: Comp.Webservice.Utils.BaseService.LogCount: Request type: Get Documentations, json: OnlyChanged:True,Type:CarePlan,SubTypeIds:[0],CustomerIds:[1004],From:2020-01-01,To:2022-01-01,Limit:1, returning: 0 objects
2021-10-01 09:10:43,683 DEBUG: Comp.ServiceStackAppHost+<>c__DisplayClass4_0.<Configure>b__2: stop 0
2021-10-01 09:11:01,890 DEBUG: Comp.ServiceStackAppHost+<>c__DisplayClass4_0.<Configure>b__1: start 1
2021-10-01 09:11:01,891 DEBUG: Comp.ServiceStackAppHost+<>c.<ConfigurePlugins>b__23_2: POST /soap12
2021-10-01 09:11:01,945 ERROR: Comp.ServiceStackAppHost.LogToLogger: Error processing: http://localhost:8183/api/soap12
System.Runtime.Serialization.SerializationException: DeserializeDataContract: Error converting type: DeserializeDataContract: Error converting type: Der ungültige Aufzählungswert "39" kann nicht in den Typ "Comp.Dto.DocumentationType" deserialisiert werden. Stellen Sie sicher, dass die erforderlichen Aufzählungswerte vorhanden und mit dem Attribut "EnumMemberAttribute" gekennzeichnet sind, wenn der Typ das Attribut "DataContractAttribute" aufweist. ---> System.Runtime.Serialization.SerializationException: DeserializeDataContract: Error converting type: Der ungültige Aufzählungswert "39" kann nicht in den Typ "Comp.Dto.DocumentationType" deserialisiert werden. Stellen Sie sicher, dass die erforderlichen Aufzählungswerte vorhanden und mit dem Attribut "EnumMemberAttribute" gekennzeichnet sind, wenn der Typ das Attribut "DataContractAttribute" aufweist. ---> System.Runtime.Serialization.SerializationException: Der ungültige Aufzählungswert "39" kann nicht in den Typ "Comp.Dto.DocumentationType" deserialisiert werden. Stellen Sie sicher, dass die erforderlichen Aufzählungswerte vorhanden und mit dem Attribut "EnumMemberAttribute" gekennzeichnet sind, wenn der Typ das Attribut "DataContractAttribute" aufweist.
   bei System.Runtime.Serialization.EnumDataContract.ReadEnumValue(String value, Int32 index, Int32 count)
   bei System.Runtime.Serialization.EnumDataContract.ReadEnumValue(XmlReaderDelegator reader)
   bei System.Runtime.Serialization.EnumDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
   bei ReadGetDocumentationsFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
   bei System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
   bei System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
   bei System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
   bei ServiceStack.Text.XmlSerializer.Deserialize(String xml, Type type)
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei ServiceStack.Text.XmlSerializer.Deserialize(String xml, Type type)
   bei ServiceStack.Serialization.DataContractSerializer.DeserializeFromString(String xml, Type type)
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei ServiceStack.Serialization.DataContractSerializer.DeserializeFromString(String xml, Type type)
   bei ServiceStack.Host.Handlers.SoapHandler.<ExecuteMessage>d__7.MoveNext()

肥皂:

<?xml version="1.0" encoding="UTF-8"?>
<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soap12:Body>
      <GetDocumentations xmlns="http://schemas.datacontract.org/2004/07/Comp" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
         <CustomerIds xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <d2p1:int>1004</d2p1:int>
         </CustomerIds>
         <From>2020-01-01T00:00:00</From>
         <Limit>1</Limit>
         <OnlyChanged>true</OnlyChanged>
         <SubTypeIds xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <d2p1:int>0</d2p1:int>
         </SubTypeIds>
         <To>2022-01-01T00:00:00</To>
         <Type>39</Type>
      </GetDocumentations>
   </soap12:Body>
</soap12:Envelope>

在这种情况下,39 是错误的。 39 必须是枚举 xy 并且它可以工作。

任何想法都是重新定义我们的 UncaughtExceptionHandlers 来构建响应并结束请求。像这样的:

            UncaughtExceptionHandlers.Add((req, res, operationName, ex) =>
            
                // write to logfile
                //build response
                res.StatusCode = (int)HttpStatusCode.BadRequest;
                res.EndRequest();
            );

应该这样处理吗?如果是的话,有人有一个很好的例子吗?

【问题讨论】:

【参考方案1】:

那个答案没有帮助。我们已经有了那个 ServiceExceptionHandlers,但是请求没有通过那个代码运行。它遇到了 UncaughtExceptionHandlers。文档对 UncaughtExceptionHandlers 说:

    //Handle Unhandled Exceptions occurring outside of Services
    //E.g. Exceptions during Request binding or in filters:

这听起来像是处理格式错误的 Soap 消息的正确方法。在这种方法中我尝试过:

    if (req.GetItem(Keywords.SoapMessage) is System.ServiceModel.Channels.Message requestMsg)
    
        req.Response.UseBufferedStream = true;
        var msgVersion = requestMsg.Version;
        using (var response = XmlWriter.Create(req.Response.OutputStream))
        
            var message = System.ServiceModel.Channels.Message.CreateMessage(
                msgVersion, new FaultCode("Receiver"), ex.ToString(), null);
            message.WriteMessage(response);
        
        req.Response.End();
    

但这不起作用,因为 req.GetItem(Keywords.SoapMessage) 为空。

那么正确的处理方式是怎样的呢?

【讨论】:

如果 ServiceStack 无法反序列化它不会有请求 SOAP 消息的请求,您将需要一种不同的方式来识别它是一个 SOAP 请求,例如通过查看请求路径信息。由于您不使用 requestMsg,因此您可以将 SOAP 1.2 的 MessageVersion.Soap12WSAddressingAugust2004 或 SOAP 1.1 的 MessageVersion.Soap11WSAddressingAugust2004 作为 msgVersion。这是一些static methods that show serializing SOAP Response Messages。【参考方案2】:

请参阅SOAP Exceptions 上的文档,我们建议使用 200 OK 响应发送错误,并在响应 DTO 的 ResponseStatus 属性中序列化错误消息。

【讨论】:

以上是关于当soap12格式错误时请求超时的主要内容,如果未能解决你的问题,请参考以下文章

System.Web.HttpException:请求超时

Heroku上NodeJs应用程序中的H12请求超时错误?

PayPal - 10001 内部错误:超时处理请求快速结帐

Dart Http 包请求超时

VBA如何捕获请求超时错误?

适用于 excel 的 BigQuery 连接器 - 请求失败:错误。无法执行查询。获取 URL 时超时