首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在ASP.NET MVC和IIS7中记录原始HTTP请求/响应

在ASP.NET MVC和IIS7中记录原始HTTP请求/响应
EN

Stack Overflow用户
提问于 2009-06-24 13:44:32
回答 15查看 102.4K关注 0票数 149

我正在编写一个web服务(使用HTTP ),出于支持的目的,我们希望能够以尽可能接近原始的在线格式(即,包括ASP.NET方法、路径、所有头和主体)的方式将请求和响应记录到数据库中。

我不确定的是如何以最少的“损坏”的方式获得这些数据。我可以通过检查HttpRequest对象的所有属性并根据它们构建一个字符串(对于响应也是如此)来重新构建我认为的请求的样子,但我真的希望获得在网络上发送的实际请求/响应数据。

我很乐意使用任何拦截机制,例如过滤器、模块等,并且解决方案可以针对IIS7。但是,我更喜欢将其仅保留在托管代码中。

有什么建议吗?

编辑:我注意到HttpRequest有一个SaveAs方法,可以将请求保存到磁盘,但它使用大量无法公开访问的内部助手方法从内部状态重建请求(这正是为什么不允许保存到用户提供的流的原因,我不知道)。因此,看起来我必须尽最大努力从对象重构请求/响应文本……叹息吧。

编辑2:请注意,我说的是整个请求,包括方法、路径、头部等。当前的响应仅查看不包含此信息的正文流。

编辑3:这里没人看问题吗?到目前为止,有五个答案,但没有一个甚至暗示有办法获得整个原始的在线请求。是的,我知道我可以从request对象中捕获输出流、头和URL以及所有这些东西。我已经在问题中说过了,请参阅:

我可以通过检查HttpRequest对象的所有属性并从它们构建一个字符串(对响应也是如此)来重新构造我认为的请求的样子,但我真的希望获得在网络上发送的实际请求/响应数据。

如果您知道完整的原始数据(包括报头、url、http方法等)只是无法检索,那么知道这一点将是有用的。同样,如果您知道如何以原始格式获取所有内容(是的,我的意思仍然是包括头文件、url、http方法等)。而不需要重建它,这就是我所问的,那么这将是非常有用的。但是告诉我我可以从HttpRequest/HttpResponse对象重构它是没有用的。我知道这个。我已经说过了。

请注意:在任何人开始说这是一个坏主意,或将限制可伸缩性等之前,我们还将在分布式环境中实现节流、顺序交付和防重放机制,因此无论如何都需要数据库日志。我不是在寻找关于这是否是一个好主意的讨论,我是在寻找如何才能做到这一点。

EN

回答 15

Stack Overflow用户

回答已采纳

发布于 2009-11-26 21:48:55

好的,所以看起来答案是“不,你不能得到原始数据,你必须从解析的对象的属性重建请求/响应”。哦,好吧,我做了重建的事情。

票数 6
EN

Stack Overflow用户

发布于 2009-11-25 04:55:20

一定要使用IHttpModule并实现BeginRequestEndRequest事件。

所有的“原始”数据都存在于HttpRequestHttpResponse之间,只是它们不是单一的原始格式。以下是构建Fiddler风格的转储所需的部分(尽可能接近原始HTTP ):

代码语言:javascript
复制
request.HttpMethod + " " + request.RawUrl + " " + request.ServerVariables["SERVER_PROTOCOL"]
request.Headers // loop through these "key: value"
request.InputStream // make sure to reset the Position after reading or later reads may fail

对于响应:

代码语言:javascript
复制
"HTTP/1.1 " + response.Status
response.Headers // loop through these "key: value"

请注意,您不能读取响应流,因此您必须向输出流添加过滤器并捕获副本。

在您的BeginRequest中,您需要添加一个响应过滤器:

代码语言:javascript
复制
HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;

filter存储在EndRequest处理程序中可以访问的位置。我建议使用HttpContext.Items。然后,可以在filter.ReadStream()中获得完整的响应数据。

然后使用装饰器模式作为流的包装器来实现OutputFilterStream

代码语言:javascript
复制
/// <summary>
/// A stream which keeps an in-memory copy as it passes the bytes through
/// </summary>
public class OutputFilterStream : Stream
{
    private readonly Stream InnerStream;
    private readonly MemoryStream CopyStream;

    public OutputFilterStream(Stream inner)
    {
        this.InnerStream = inner;
        this.CopyStream = new MemoryStream();
    }

    public string ReadStream()
    {
        lock (this.InnerStream)
        {
            if (this.CopyStream.Length <= 0L ||
                !this.CopyStream.CanRead ||
                !this.CopyStream.CanSeek)
            {
                return String.Empty;
            }

            long pos = this.CopyStream.Position;
            this.CopyStream.Position = 0L;
            try
            {
                return new StreamReader(this.CopyStream).ReadToEnd();
            }
            finally
            {
                try
                {
                    this.CopyStream.Position = pos;
                }
                catch { }
            }
        }
    }


    public override bool CanRead
    {
        get { return this.InnerStream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return this.InnerStream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return this.InnerStream.CanWrite; }
    }

    public override void Flush()
    {
        this.InnerStream.Flush();
    }

    public override long Length
    {
        get { return this.InnerStream.Length; }
    }

    public override long Position
    {
        get { return this.InnerStream.Position; }
        set { this.CopyStream.Position = this.InnerStream.Position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return this.InnerStream.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        this.CopyStream.Seek(offset, origin);
        return this.InnerStream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        this.CopyStream.SetLength(value);
        this.InnerStream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        this.CopyStream.Write(buffer, offset, count);
        this.InnerStream.Write(buffer, offset, count);
    }
}
票数 92
EN

Stack Overflow用户

发布于 2012-03-09 16:31:37

HttpRequest上的以下扩展方法将创建一个字符串,该字符串可以粘贴到fiddler中并重放。

代码语言:javascript
复制
namespace System.Web
{
    using System.IO;

    /// <summary>
    /// Extension methods for HTTP Request.
    /// <remarks>
    /// See the HTTP 1.1 specification http://www.w3.org/Protocols/rfc2616/rfc2616.html
    /// for details of implementation decisions.
    /// </remarks>
    /// </summary>
    public static class HttpRequestExtensions
    {
        /// <summary>
        /// Dump the raw http request to a string. 
        /// </summary>
        /// <param name="request">The <see cref="HttpRequest"/> that should be dumped.       </param>
        /// <returns>The raw HTTP request.</returns>
        public static string ToRaw(this HttpRequest request)
        {
            StringWriter writer = new StringWriter();

            WriteStartLine(request, writer);
            WriteHeaders(request, writer);
            WriteBody(request, writer);

            return writer.ToString();
        }

        private static void WriteStartLine(HttpRequest request, StringWriter writer)
        {
            const string SPACE = " ";

            writer.Write(request.HttpMethod);
            writer.Write(SPACE + request.Url);
            writer.WriteLine(SPACE + request.ServerVariables["SERVER_PROTOCOL"]);
        }

        private static void WriteHeaders(HttpRequest request, StringWriter writer)
        {
            foreach (string key in request.Headers.AllKeys)
            {
                writer.WriteLine(string.Format("{0}: {1}", key, request.Headers[key]));
            }

            writer.WriteLine();
        }

        private static void WriteBody(HttpRequest request, StringWriter writer)
        {
            StreamReader reader = new StreamReader(request.InputStream);

            try
            {
                string body = reader.ReadToEnd();
                writer.WriteLine(body);
            }
            finally
            {
                reader.BaseStream.Position = 0;
            }
        }
    }
}
票数 52
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1038466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档