记录的原HTTP请求/应答ASP.NET 视&IIS7
-
10-07-2019 - |
题
我正在写一个网络服务(使用ASP.NET 视)和支持的目的,我们想要能够登录的请求和响应在尽可能靠近原料、在线格式(i。e包括HTTP方法、路径,所有头和身体)成一个数据库。
什么我不能肯定的是如何得到保持这个数据在少'错位的'方式。我可以重新构成我相信该请求看起来像通过检查所有的性质 HttpRequest
对象和建立一个串从他们(和同样的响应),但我真的很想得到的实际请求/回应的数据,在线。
我乐于使用的任何拦截机制,如过滤器、模块等等。和解可以是特定于IIS7.但是,我宁愿保留它在管理代码只。
任何建议?
编辑: 我注意到, HttpRequest
有一个 SaveAs
方法,该方法可以节省的请求磁盘,但这种重建的请求从内部国家使用一种负荷的内部辅助方法,不可公开访问(相当为什么这个不允许保存到一个用户提供的流我不知道)。所以它开始看起来像我得做我最好的重建请求/应答案文的对象...呻吟。
编辑2: 请注意,我说的 整个 请求包括方法、路径、标题等。目前的反应仅仅看看身体流,其中不包括这一信息。
编辑3: 没人读的问题在这里?五个答案迄今为止,尚没有一个甚至暗示方式得到整个原始的在线请求。是的,我知道我可以捕捉的输出流和标题和URL和所有的东西从该请求的对象。我已经说过,在这个问题,参见:
我可以重新构成我相信该请求看起来像通过检查所有的属性http请求的对象和建立一个串从他们(和同样的响应),但我真的很想得到的实际请求/回应的数据,在线。
如果你知道的 完整的 原始数据(包括标题、url http方法,等等)。 只是不能被检索,那将是有用的,要知道。同样,如果你知道如何得到这一切的原始格式(是的,我仍意味着包括标题、url http方法,等等)。 无需重建它,这是我的要求,那么这将是非常有用的。但是,告诉我,我可以重建它的 HttpRequest
/HttpResponse
对象是没有用的。我知道这一点。我已经说过它。
请注意:之前任何人开始说这是个坏主意,或将限制扩展,等等, 我们也将实施的限制、循序递送,并防重播机制在一个分散的环境,使数据库记录所需的无论如何。我不是在寻找一个讨论是否这是一个很好的想法,我正在寻找它如何可以做到的。
解决方案 7
OK,所以它看起来像答案是“不,你不能得到的原始数据,你必须重建从解析对象的属性的请求/响应”。噢,我已经做了重建的事情。
其他提示
绝对使用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"
请注意您无法读取响应流让你有一个过滤器添加到输出流并获取副本。
在你的filter
,你将需要添加一个响应滤波器:
HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;
商店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);
}
}
上的HttpRequest将创建可以粘贴到提琴手和重放的字符串下面的扩展方法。
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;
}
}
}
}
您可以使用ALL_RAW服务器变量获得与请求发送的原始HTTP头,那么你就可以得到的InputStream和往常一样:
string originalHeader = HttpHandler.Request.ServerVariables["ALL_RAW"];
检查出: http://msdn.microsoft的.com / EN-US /库/ ms524602%28VS.90%29.aspx
好吧,我工作的一个项目,做了,也许不是太深,使用请求参数日志:
请看:
public class LogAttribute : ActionFilterAttribute
{
private void Log(string stageName, RouteData routeData, HttpContextBase httpContext)
{
//Use the request and route data objects to grab your data
string userIP = httpContext.Request.UserHostAddress;
string userName = httpContext.User.Identity.Name;
string reqType = httpContext.Request.RequestType;
string reqData = GetRequestData(httpContext);
string controller = routeData["controller"];
string action = routeData["action"];
//TODO:Save data somewhere
}
//Aux method to grab request data
private string GetRequestData(HttpContextBase context)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < context.Request.QueryString.Count; i++)
{
sb.AppendFormat("Key={0}, Value={1}<br/>", context.Request.QueryString.Keys[i], context.Request.QueryString[i]);
}
for (int i = 0; i < context.Request.Form.Count; i++)
{
sb.AppendFormat("Key={0}, Value={1}<br/>", context.Request.Form.Keys[i], context.Request.Form[i]);
}
return sb.ToString();
}
您可以装饰你的控制器类完全记录它:
[Log]
public class TermoController : Controller {...}
或日志只是一些个别动作方法
[Log]
public ActionResult LoggedAction(){...}
任何理由需要保持它在托管的代码?
值得一提的是,可以启用 失败的跟踪记录 在IIS7如果你不喜欢重新发明车轮。这个日志的标题、请求和响应体以及许多其他的事情。
我去McKAMEY的做法。下面是我写的一个模块,这将让你开始,希望为您节省一些时间。你需要的东西,你的作品明显堵塞记录仪:
public class CaptureTrafficModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
OutputFilterStream filter = new OutputFilterStream(app.Response.Filter);
app.Response.Filter = filter;
StringBuilder request = new StringBuilder();
request.Append(app.Request.HttpMethod + " " + app.Request.Url);
request.Append("\n");
foreach (string key in app.Request.Headers.Keys)
{
request.Append(key);
request.Append(": ");
request.Append(app.Request.Headers[key]);
request.Append("\n");
}
request.Append("\n");
byte[] bytes = app.Request.BinaryRead(app.Request.ContentLength);
if (bytes.Count() > 0)
{
request.Append(Encoding.ASCII.GetString(bytes));
}
app.Request.InputStream.Position = 0;
Logger.Debug(request.ToString());
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
Logger.Debug(((OutputFilterStream)app.Response.Filter).ReadStream());
}
private ILogger _logger;
public ILogger Logger
{
get
{
if (_logger == null)
_logger = new Log4NetLogger();
return _logger;
}
}
public void Dispose()
{
//Does nothing
}
}
使用 IHttpModule的:
namespace Intercepts
{
class Interceptor : IHttpModule
{
private readonly InterceptorEngine engine = new InterceptorEngine();
#region IHttpModule Members
void IHttpModule.Dispose()
{
}
void IHttpModule.Init(HttpApplication application)
{
application.EndRequest += new EventHandler(engine.Application_EndRequest);
}
#endregion
}
}
class InterceptorEngine
{
internal void Application_EndRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpResponse response = application.Context.Response;
ProcessResponse(response.OutputStream);
}
private void ProcessResponse(Stream stream)
{
Log("Hello");
StreamReader sr = new StreamReader(stream);
string content = sr.ReadToEnd();
Log(content);
}
private void Log(string line)
{
Debugger.Log(0, null, String.Format("{0}\n", line));
}
}
如果偶尔使用,避开狈,怎么样东西原油象下面这样?
Public Function GetRawRequest() As String
Dim str As String = ""
Dim path As String = "C:\Temp\REQUEST_STREAM\A.txt"
System.Web.HttpContext.Current.Request.SaveAs(path, True)
str = System.IO.File.ReadAllText(path)
Return str
End Function
你可以完成这个 DelegatingHandler
没有用的 OutputFilter
中提到的其他答复。净额4.5使用 Stream.CopyToAsync()
功能。
我不知道的细节,但是它没有触发的所有坏事发生时你的尝试直接读取响应流。
例如:
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
DoLoggingWithRequest(request);
var response = await base.SendAsync(request, cancellationToken);
await DoLoggingWithResponse(response);
return response;
}
private async Task DologgingWithResponse(HttpResponseMessage response) {
var stream = new MemoryStream();
await response.Content.CopyToAsync(stream).ConfigureAwait(false);
DoLoggingWithResponseContent(Encoding.UTF8.GetString(stream.ToArray()));
// The rest of this call, the implementation of the above method,
// and DoLoggingWithRequest is left as an exercise for the reader.
}
}
我知道这不是托管代码,但我要建议的ISAPI筛选器。这是一个两三年,因为我之前和ASP.Net做这件事后有“乐趣”保持我自己的ISAPI,但据我记得你可以得到所有这些东西的访问。
http://msdn.microsoft.com/en-us/library /ms524610.aspx
如果一个HTTP模块是不够的,你需要什么,然后我不认为这是在所需的详细金额这样做的任何管理方式。这会是一个痛苦的,虽然做的。
我同意他人,使用IHttpModule的。看看在这个问题的答案,这确实几乎你都在问同样的事情。它记录的请求和响应,但没有报头。
这可能是最好的做您的应用程序之外。您可以设置一个反向代理做这样的事情(以及更多)。反向代理基本上是在您的服务器机房位于一个Web服务器和Web服务器(S)和客户端之间的立场。请参阅 http://en.wikipedia.org/wiki/Reverse_proxy
同意FigmentEngine,IHttpModule
似乎是去的方式。
看到httpworkerrequest
,readentitybody
和GetPreloadedEntityBody
要获得inApp
你需要这样做:
(HttpWorkerRequest)inApp.Context.GetType().GetProperty("WorkerRequest", bindingFlags).GetValue(inApp.Context, null);
其中<=>是HttpApplication对象。
HttpRequest
和HttpResponse
预MVC用于具有GetInputStream()
和GetOutputStream()
可能被用于该目的。有没有考虑在MVC的一部分,所以我不确定他们是availavle但可能是一个想法:)