web api 記錄請求

来源:http://www.cnblogs.com/pengei/archive/2016/09/30/5924188.html
-Advertisement-
Play Games

前段時間在開發一個協議站點供客戶端(Android/IOS)使用,因業務需要統計各協議的調用頻率。將記錄以日誌的形式記錄在日誌系統中。 簡單分析了一下,技術方案大致分為兩種: 方案A:每個業務模塊需要埋點的協議單獨埋點。 方案B:封裝一個HttpModule。記錄所有的請求。 方案A與方案B的優缺點... ...


前段時間在開發一個協議站點供客戶端(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>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本系列將以一個實際項目為背景,介紹如何使用ADFS3.0實現SSO。其中包括SharePoint,MVC,Exchange等應用程式的SSO集成。 整個系列將會由如下幾個部分構成: 實戰:ADFS3.0單點登錄系列-總覽 實戰:ADFS3.0單點登錄系列-前置準備 實戰:ADFS3.0單點登錄系列- ...
  • Linux find命令用來在指定目錄下查找文件。 命令組成:find [搜索目錄] [參數] [文件屬性] 參數說明: -name:文件名稱符合 name 的文件。-iname 會忽略大小寫 舉例說明: a. 搜索範圍從根目錄開始,搜索文件1.txt:find / -name 1.txt b. 搜 ...
  • mysql 安裝就簡單多了,可以通過 ubuntu 的包管理從源直接下載 輸入 “Y” ,然後輸入輸入資料庫 root 用戶的密碼,然後就完成了。 接下來打開 mysql ,輸入之前設定的密碼即可。 MySQL的一些簡單管理: 啟動MySQL服務: sudo start mysql 停止MySQL服 ...
  • 現在要實現一個例會簡訊群發通知的功能,所有被通知對象信息均存於Mysql中,應用架構採用asp.net MVC 。 ...
  • .net core現在已經有了大的發展,雖然筆者現在已經從事python開發,但是一直在關註.net的發展,在逛博客園的時候,發現有大家都會提到Nancy這個框架,在簡單的使用之後,發現竟然是如此的簡單而優雅 代碼已經上傳到git上,包含源代碼和docker打包腳本,大家有興趣可以自行研究 http ...
  • 最近看來是跟聲音幹上了啊! 音頻轉換的第二種方法,這種方法相對第一種來說,要簡單的多! 首先,你得下載個“ffmpeg.exe” 插件,然後把它放到你的項目中,如下圖: 程式中會調用該文件,以助於轉換音頻格式! 上代碼: 接著來張效果圖: 好了,就這麼簡單,不要不敢不相信你的眼睛,其實就是這麼簡單! ...
  • 一直想自己開發個博客 所以學習了下其他博主的開發個人博客文章 就開始了 ...
  • 通過昨天對EF貪婪載入和延遲載入的學習,不難發現,延遲載入還是很好用的,但是問題也就來了,有的時候我們只需要載入一個實體,不需要和他相關的外部實體,這時候我們來看看EF延遲載入時怎麼作用的吧 打開profiler 在Main函數入口處寫一個查詢,在Console.Read();處打一個斷點 在pro ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...