NetCore 中间件获取请求报文和返回报文
using System;
using System.IO; namespace WebApi.Restful.Middlewares
{
public class MemoryWrappedHttpResponseStream : MemoryStream
{
private Stream _innerStream;
public MemoryWrappedHttpResponseStream(Stream innerStream)
{
this._innerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream));
}
public override void Flush()
{
this._innerStream.Flush();
base.Flush();
} public override void Write(byte[] buffer, int offset, int count)
{
base.Write(buffer, offset, count);
this._innerStream.Write(buffer, offset, count);
} protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
this._innerStream.Dispose();
}
} public override void Close()
{
base.Close();
this._innerStream.Close();
}
}
}
using Exceptionless;
using gateway.api;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace WebApi.Restful.Middlewares
{ /// <summary>
/// 请求日志记录中间件
/// </summary>
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public RequestLoggingMiddleware(RequestDelegate next,
ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger; } public async Task Invoke(HttpContext context)
{
context.TraceIdentifier = Guid.NewGuid().ToString("N"); var request = context.Request; await RequestEnableRewindAsync(request).ConfigureAwait(false);
var encoding = GetRequestEncoding(request);
var requestContent = await ReadStreamAsync(request.Body, encoding).ConfigureAwait(false);
WritLog(context, JsonConvert.SerializeObject(requestContent)); await ResponseEnableRewindAsync(context.Response);
context.Response.OnCompleted(ResponseCompletedCallback, context);
await _next(context);
} private async Task ResponseCompletedCallback(object obj)
{
if (obj is HttpContext context)
{
var response = await ResponseReadStreamAsync(context.Response);
//记录日志
//ExceptionlessClient.Default.CreateLog(JsonConvert.SerializeObject(response)).AddTags(context.TraceIdentifier).Submit();
} }
private async Task<string> ResponseReadStreamAsync(HttpResponse response)
{
if (response.Body.Length > 0)
{
response.Body.Seek(0, SeekOrigin.Begin);
var encoding = GetEncoding(response.ContentType);
var retStr = await ReadStreamAsync(response.Body, encoding, false).ConfigureAwait(false);
return retStr;
}
return null;
}
private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding, bool forceSeekBeginZero = true)
{
using (StreamReader sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放
{
var str = await sr.ReadToEndAsync();
if (forceSeekBeginZero)
{
stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取
}
return str;
}
}
private void WritLog(HttpContext context, string body)
{
var request = context.Request;
try
{
Task.Factory.StartNew(() =>
{
LogMode logMode = new LogMode
{
Body = body,
CententLength = request.ContentLength,
CententType = request.ContentType,
Headers = JsonConvert.SerializeObject(request.Headers),
Host = request.Host.Host,
Method = request.Method,
Path = request.Path,
Query = JsonConvert.SerializeObject(request.Query)
};
// 记录日志
// ExceptionlessClient.Default.CreateLog(JsonConvert.SerializeObject(logMode)).AddTags(context.TraceIdentifier).Submit();
});
}
catch (Exception ex)
{
//记录日志
//ex.ToExceptionless().Submit();
} } private async Task ResponseEnableRewindAsync(HttpResponse response)
{
if (!response.Body.CanRead || !response.Body.CanSeek)
{
response.Body = new MemoryWrappedHttpResponseStream(response.Body);
}
} private async Task RequestEnableRewindAsync(HttpRequest request)
{
if (!request.Body.CanSeek)
{
request.EnableBuffering(); await request.Body.DrainAsync(CancellationToken.None);
request.Body.Seek(0L, SeekOrigin.Begin);
}
} private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding)
{
using (StreamReader sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放
{
var str = await sr.ReadToEndAsync();
stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取
return str;
}
} private Encoding GetRequestEncoding(HttpRequest request)
{
var requestContentType = request.ContentType;
var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType);
var requestEncoding = requestMediaType.Encoding;
if (requestEncoding == null)
{
requestEncoding = Encoding.UTF8;
}
return requestEncoding;
} private Encoding GetEncoding(string contentType)
{
var mediaType = contentType == null ? default(MediaType) : new MediaType(contentType);
var encoding = mediaType.Encoding;
if (encoding == null)
{
encoding = Encoding.UTF8;
}
return encoding;
}
public class LogMode
{
public string Body { get; set; }
public long? CententLength { get; set; }
public string CententType { get; set; }
public string Headers { get; set; }
public string Host { get; set; }
public string Method { get; set; }
public string Path { get; set; }
public string Query { get; set; }
} private Dictionary<string, IEnumerable<string>> GetHeaders(HttpRequestMessage request)
{
var result = new Dictionary<string, IEnumerable<string>>();
foreach (var pair in request.Headers)
{
result.Add(pair.Key, pair.Value);
}
return result;
}
}
}
NetCore 中间件获取请求报文和返回报文的更多相关文章
- spring-boot 使用Aop通知打印控制器请求报文和返回报文
一.简介 开发过程中我们往往需要写许多例如: @GetMapping("/id/get") public Result getById( String id) throws Exc ...
- .net core webapi通过中间件获取请求和响应内容
本文主要根据中间件来实现对.net core webapi中产生的请求和响应数据进行获取并存入日志文件中: 这里不详细介绍日志文件的使用.你可以自己接入NLog,log4net,Exceptionle ...
- 切面(Aspect)获取请求参数和返回值
@Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求, ...
- django中间件(获取请求ip)
def simple_middleware(get_response): # 此处编写的代码仅在Django第一次配置和初始化的时候执行一次. print('1----django启动了') def ...
- HTTP的请求报文与响应报文
报文: 简单来说,报文就是也就是HTTP报文,作用是在各个系统之间进行和响应时用来交换与传输的数据单元,即站点一次性要发送的数据块,这些数据块以一些文本形式的元信息开头,这些信息描述了报文的内容及含义 ...
- 调用中行接口针对返回报文(xml形式)做相关处理
最近在对接中行银行接口,在获取返回报文的时候遇到一些问题,现在在这里做个总结 TIP: 在返回报文之前,要对前置机的URL请求,在这期间遇到一个坑,还是通过查看日志才发现问题 在填写转账信息的时候要求 ...
- HTTP请求报文、响应报文
HTTP请求报文 HTTP请求报文由3部分组成(请求行+请求头+请求体): 请求行:①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE.HEAD.OPTIONS.PUT. ...
- 重温Http协议--请求报文和响应报文
http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...
- 关于HTTP请求报文和响应报文学习笔记
超文本传输协议(Hypertext Transfer Protocol,简称HTTP)是应用层的一种通信协议.它是一种请求/响应式的协议,即一个客户端与服务器建立连接后,向服务器发送一个请求;服务器接 ...
随机推荐
- MyBatis 模板
mybatis-config.xml: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE co ...
- WPF MvvmLight简单实例(1) 页面导航
原文:WPF MvvmLight简单实例(1) 页面导航 实现了那些功能,先看看截图: 操作描述: 在程序运行后,点击“Load”按钮,页面会加载PageOne,点击PageOne页面中的“Next” ...
- PMC另类阐述
生产部门,坦克,铠甲战士,血厚硬气 业务部门,刺客,杀气十足,强势收割人头 采购部门,法师,在坦克身后持续输出 PMC,辅助,血不够厚扛不了伤害,输出不够拿不到人头,是团队中最容易被忽视的角色 坦克和 ...
- 财富500强的前10个公司里有8个公司在使用Qt(Qt自己认为的优点是:直觉主义、跨平台、节省时间),以及一些商业案例
8 of Top 10 Fortune 500 use Qt Qt is the software development framework of choice by engineers in ov ...
- Chinese Messy Code of String
It's very strange that I found the messy code.I 've never seen this before. this is the java code: / ...
- nginx 简单应用
从源代码编译 Nginx 把源码解压缩之后,在终端里运行如下命令: $ ./configure $ make $ sudo make install 默认情况下,Nginx 会被安装在 /usr/lo ...
- Android零基础入门第72节:SwipeRefreshLayout下拉刷新
在实际开发中,经常都会遇到下拉刷新.上拉加载更多的情形,这一期就一起来学习Android系统的SwipeRefreshLayout下拉刷新组件. 一.SwipeRefreshLayout简介 Swip ...
- Qt给应用程序添加版本信息(对rc文件的设置,可利用QT内置变量)
作者:daodaoliang 时间:2016年7月11日16:12:09 版本:V 0.0.4 邮箱:daodaoliang@yeah.net 0. 环境说明 系统环境: win10 64位 Qt环境 ...
- 请给出linux中查看系统已经登录用户的命令?
w命令 第一行:当前系统运行了多久和系统负载 谁正在远程登录系统并且在干什么 [root@martin ~]# w 11:30:33 up 4 days, 18:10, 2 users, load a ...
- spring 5.x 系列第12篇 —— 整合memcached (代码配置方式)
文章目录 一.说明 1.1 XMemcached客户端说明 1.2 项目结构说明 1.3 依赖说明 二.spring 整合 memcached 2.1 单机配置 2.2 集群配置 2.3 存储基本类型 ...