在异常期间捕获原始 HTTP POST 数据

Posted

技术标签:

【中文标题】在异常期间捕获原始 HTTP POST 数据【英文标题】:Capturing raw HTTP POST Data during Exception 【发布时间】:2010-10-28 18:03:47 【问题描述】:

我有一个托管在 IIS/ASP.NET 中的 WCF 服务,它接受序列化对象的 HTTP 发布(不是表单发布)。

如果客户端发送格式错误的请求(例如,它们没有正确序列化对象),我想记录发送的消息。

我们已经在使用 ELMAH 来捕获未处理的异常,因此简单地附加发布数据将是最简单的选择。

我可以在异常期间获取当前的 HttpContext,但这仅包含 HTTP 标头信息。

我的问题是:有什么方法可以捕获原始的 HTTP POST 请求正文吗?或者,失败了 - 捕获导致错误的输入的更好方法(没有反向代理)?

编辑:澄清一下,始终运行数据包级捕获并不适合。我正在寻找一个可以部署到生产服务器的解决方案,该解决方案将使客户端超出我们的控制或监控能力。

编辑#2:建议访问 Request.InputStream - 如果您在 WCF 从流中读取请求后尝试读取,这将不起作用。

这里有一段代码示例,可以查看我是如何尝试使用它的。

        StringBuilder log = new StringBuilder();

        var request = HttpContext.Current.Request;

        if (request.InputStream != null)
        
            log.AppendLine(string.Format("request.InputStream.Position = \"0\"", request.InputStream.Position));
            if (request.InputStream.Position != 0)
            
                request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
            

            using (StreamReader sr = new StreamReader(request.InputStream))
            
                log.AppendLine(string.Format("Original Input: \"0\"", sr.ReadToEnd()));
            
        
        else
        
            log.AppendLine("request.Inputstream = null");
        


        log.ToString();

log.ToString() 的输出是:

request.InputStream.Position = "0" 原始输入:“”

【问题讨论】:

StreamReader 的“使用”将导致 System.Web.Request.InputStream 被释放(这意味着数据丢失)。 【参考方案1】:

当它到达您的服务时,请求已被处理,您无法使用。

但是...您可以附加message inspector。消息检查器允许您在消息到达您的操作实现之前对其进行处理。您可以创建消息的缓冲副本,并将其复制到 OperationContext.Current。

当然是丑陋的 hack,这意味着内存开销,因为现在每个请求都有两个消息副本浮动。

【讨论】:

谢谢 - 这不是一个特别好的解决方案,但牺牲一些内存可能是值得的。【参考方案2】:

您是否查看了 System.Web.Request.InputStream 属性?它应该有你想要的。

如何“倒回” InputStream 属性。

    if (Request.InputStream.Position != 0)
    
        Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
    

您应该考虑的另一个选项是在 BeginRequest 事件上使用 HTTPModule 捕获此信息。数据应该在 BeginRequest 事件中存在,因为我不相信 WCF 会在 PostAuthenticateEvent 之后接收请求。

【讨论】:

我确实看过该属性 - 不幸的是,该流仅包含未读数据。到异常发生时,WCF 已经读取了输入数据。您不能倒带/重置位置。 查看我的更新...由于 Request.InputStream.CanSeek 为真,您可以使用 Seek 方法将位置重置回 0。 感谢您的更新 - CanSeek 是正确的,但是流中仍然没有任何内容可供读取。请参阅更新的文本,了解我为尝试和测试所做的工作。【参考方案3】:

在 ASP.NET(IIS 下的 ASP Web 服务)下,以下代码有帮助:

if (request.InputStream.Position != 0)

  request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);

WCF 可能不同(即在读取后 Dispose InputStream)

【讨论】:

这与杰夫给出的答案相同。它也不起作用,因为流不可搜索。【参考方案4】:

使用提琴手。免于 MS。效果很好。

【讨论】:

我说的是当没有 Fiddler、Wireshark 或其他任何运行来捕获它时发生的错误。例如,在无法一直运行数据包捕获的生产或登台服务器上。

以上是关于在异常期间捕获原始 HTTP POST 数据的主要内容,如果未能解决你的问题,请参考以下文章

CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常

CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常

Swift CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。

架构比较 - 填充源模型期间捕获的意外异常:对象引用未设置为实例对象

在 JSON.parse 期间在节点中捕获异常

如何在 Tensorflow 2 中的模型训练期间捕获任何异常