你的位置:首页 > ASP.net教程

[ASP.net教程]web api 记录请求


前段时间在开发一个协议站点供客户端(Android/IOS)使用,因业务需要统计各协议的调用频率。将记录以日志的形式记录在日志系统中。

  简单分析了一下,技术方案大致分为两种:

  方案A:每个业务模块需要埋点的协议单独埋点。

  方案B:封装一个HttpModule。记录所有的请求。

  方案A与方案B的优缺点就不在分析了。在我们的项目有两个个小组做类似的协议站点,我们采用的是方案B。而另外的一个小组采用方案A。

  在此我重点说一下采用的方案B的理由:

    1、麻烦一个人,一个人开发完毕后,其他人不再去花时间增加记录。统一记录。

    2、方便排错,还可以做请求参数与输出参数的记录,也不用在业务中记录返回的值。业务开发只关心业务即可。记录业务中的常规日志即可。

  代码比较简单。与协议之间走的是Post请求发送Json串。请求串全在Request.InputStream中。两个文件一个处理请求(Handle.cs),一个获取数据(CatchTextStream.cs)

Handle.cs

using System;using System.IO;using System.Web;using Logs;namespace HttpModule.Api{  public class Handle : IHttpModule  {    private string json = string.Empty;    private string requestItemKey = "request.json";    private string responseItemKey = "response.json";    void IHttpModule.Dispose()    {    }    void IHttpModule.Init(HttpApplication context)    {      context.BeginRequest += new EventHandler(beginRequest);      context.EndRequest += new EventHandler(endRequest);    }    private void beginRequest(object sender, EventArgs e)    {      HttpApplication application = (HttpApplication)sender;      var context = application.Context;      if (context == null)      {        return;      }      //排除不需要的链接      if (context.Request.InputStream.Length > 0)      {        context.Response.Filter = new CatchTextStream(context.Response.Filter, responseItemKey);        context.Request.InputStream.Position = 0; //设置流的位置        StreamReader reader = new StreamReader(context.Request.InputStream); //request请求流        string json = reader.ReadToEnd();        context.Request.InputStream.Seek(0, SeekOrigin.End);//重置流读取位置,如果不重置在方法中无法获取json串        context.Request.RequestContext.HttpContext.Items[requestItemKey] = json;      }      else//只记录请求参数      {        _log.Info("请求url:" + context.Request.Url);      }    }    private void endRequest(object sender, EventArgs e)    {      HttpApplication application = (HttpApplication)sender;      var context = application.Context;      if (context.Request.RequestContext.HttpContext.Items.Contains(requestItemKey))      {        string requestJson = context.Request.RequestContext.HttpContext.Items[requestItemKey].ToString();        string responseJson = context.Request.RequestContext.HttpContext.Items[responseItemKey].ToString();        //当前请求状态 返回值中带code:0表示协议请求成功 status=日志系统使用标识,1=请求正常返回,0=请求异常        int status = responseJson.Contains("\"code\":\"0\"") ? 1 : 0;        writeLog(context.Request.Url.LocalPath, requestJson, "return=" + responseJson, status);      }    }    private void writeLog(string url, string parms, string msg, int status)    {      var entity = new Logs.LogRecord("站点名称", LogLevelType.Monitor, url)      {        ParasNameValue = parms,        ErrMessage = msg,        Status = status      };      Logs.LogNetHelper.WriteLog(entity);    }  }}

注:Logs包为公司项目封装的通用记录方法。

CatchTextStream.cs

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Runtime.InteropServices;using System.Text;using System.Threading.Tasks;using System.Web;namespace HttpModule.Api{  class CatchTextStream : Stream  {    private Stream output;    private List<byte> _listByte = new List<byte>();    private string _itemKey;    public CatchTextStream(Stream s, string itemKey)    {      _itemKey = itemKey;      output = s;    }    public override bool CanRead    {      get { return output.CanRead; }    }    public override bool CanSeek    {      get { return output.CanSeek; }    }    public override bool CanWrite    {      get { return output.CanWrite; }    }    public override void Flush()    {      output.Flush();      if (_listByte.Any())      {        var utf8 = Encoding.UTF8;        string json = utf8.GetString(_listByte.ToArray(), 0, _listByte.Count);        HttpContext.Current.Request.RequestContext.HttpContext.Items[_itemKey] = json;      }    }    public override long Length    {      get { return output.Length; }    }    public override long Position    {      get { return output.Position; }      set { output.Position = value; }    }    public override int Read(byte[] buffer, int offset, int count)    {      return output.Read(buffer, offset, count);    }    public override long Seek(long offset, SeekOrigin origin)    {      return output.Seek(offset, origin);    }    public override void SetLength(long value)    {      output.SetLength(value);    }    public override void Write(byte[] buffer, int offset, int count)    {      output.Write(buffer, offset, count);      if (HttpContext.Current != null)      {        if (HttpContext.Current.Request.RequestContext.HttpContext.Items.Contains(_itemKey))        {          var temp = buffer.Skip(offset).Take(count);          _listByte.AddRange(temp);        }      }    }  }}

接下来在Web.config配置Modules即可。

<modules runAllManagedModulesForAllRequests="true">   <!--记录请求日志-->   <add name="apilog" type="HttpModule.Api.Handle,HttpModule.Api" /> </modules>