我正在编写一个web服务(使用HTTP ),出于支持的目的,我们希望能够以尽可能接近原始的在线格式(即,包括ASP.NET方法、路径、所有头和主体)的方式将请求和响应记录到数据库中。
我不确定的是如何以最少的“损坏”的方式获得这些数据。我可以通过检查HttpRequest
对象的所有属性并根据它们构建一个字符串(对于响应也是如此)来重新构建我认为的请求的样子,但我真的希望获得在网络上发送的实际请求/响应数据。
我很乐意使用任何拦截机制,例如过滤器、模块等,并且解决方案可以针对IIS7。但是,我更喜欢将其仅保留在托管代码中。
有什么建议吗?
编辑:我注意到HttpRequest
有一个SaveAs
方法,可以将请求保存到磁盘,但它使用大量无法公开访问的内部助手方法从内部状态重建请求(这正是为什么不允许保存到用户提供的流的原因,我不知道)。因此,看起来我必须尽最大努力从对象重构请求/响应文本……叹息吧。
编辑2:请注意,我说的是整个请求,包括方法、路径、头部等。当前的响应仅查看不包含此信息的正文流。
编辑3:这里没人看问题吗?到目前为止,有五个答案,但没有一个甚至暗示有办法获得整个原始的在线请求。是的,我知道我可以从request对象中捕获输出流、头和URL以及所有这些东西。我已经在问题中说过了,请参阅:
我可以通过检查HttpRequest对象的所有属性并从它们构建一个字符串(对响应也是如此)来重新构造我认为的请求的样子,但我真的希望获得在网络上发送的实际请求/响应数据。
如果您知道完整的原始数据(包括报头、url、http方法等)只是无法检索,那么知道这一点将是有用的。同样,如果您知道如何以原始格式获取所有内容(是的,我的意思仍然是包括头文件、url、http方法等)。而不需要重建它,这就是我所问的,那么这将是非常有用的。但是告诉我我可以从HttpRequest
/HttpResponse
对象重构它是没有用的。我知道这个。我已经说过了。
请注意:在任何人开始说这是一个坏主意,或将限制可伸缩性等之前,我们还将在分布式环境中实现节流、顺序交付和防重放机制,因此无论如何都需要数据库日志。我不是在寻找关于这是否是一个好主意的讨论,我是在寻找如何才能做到这一点。
发布于 2009-11-26 21:48:55
好的,所以看起来答案是“不,你不能得到原始数据,你必须从解析的对象的属性重建请求/响应”。哦,好吧,我做了重建的事情。
发布于 2009-11-25 04:55:20
一定要使用IHttpModule
并实现BeginRequest
和EndRequest
事件。
所有的“原始”数据都存在于HttpRequest
和HttpResponse
之间,只是它们不是单一的原始格式。以下是构建Fiddler风格的转储所需的部分(尽可能接近原始HTTP ):
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
对于响应:
"HTTP/1.1 " + response.Status
response.Headers // loop through these "key: value"
请注意,您不能读取响应流,因此您必须向输出流添加过滤器并捕获副本。
在您的BeginRequest
中,您需要添加一个响应过滤器:
HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;
将filter
存储在EndRequest
处理程序中可以访问的位置。我建议使用HttpContext.Items
。然后,可以在filter.ReadStream()
中获得完整的响应数据。
然后使用装饰器模式作为流的包装器来实现OutputFilterStream
:
/// <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);
}
}
发布于 2012-03-09 16:31:37
HttpRequest上的以下扩展方法将创建一个字符串,该字符串可以粘贴到fiddler中并重放。
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;
}
}
}
}
https://stackoverflow.com/questions/1038466
复制相似问题