Asp.net-Core
如何檢索目前響應正文長度?
我需要檢索響應正文長度。
當我查看https://github.com/aspnet/HttpAbstractions/wiki/Rolling-Notes-Response-Stream-Contract時,據說:
Stream.Position {get} 和 Stream.Length {get} 返回寫入的累積字節數
這正是我所需要
httpContext.Response.Body.Length的,但會引發NotSupportedException並說“流不可搜尋”。我應該使用委託流來計算每次寫入的字節數嗎?
這是在流寫入期間跟踪內容長度的程式碼。該類
ContentLengthTracker旨在在其他類之間共享內容長度值。程式碼發佈在https://github.com/ycrumeyrolle/Throttling/blob/master/src/Throttling/Internal/ContentLengthTrackingStream.csusing System; using System.IO; using System.Threading; using System.Threading.Tasks; public class ContentLengthTracker { public long ContentLength { get; set; } } public class ContentLengthTrackingStream : Stream { private readonly Stream _inner; private readonly ContentLengthTracker _tracker; public ContentLengthTrackingStream(Stream inner, ContentLengthTracker tracker) { if (inner == null) { throw new ArgumentNullException(nameof(inner)); } if (tracker == null) { throw new ArgumentNullException(nameof(tracker)); } _inner = inner; _tracker = tracker; } public override bool CanRead => _inner.CanRead; public override bool CanSeek => _inner.CanSeek; public override bool CanWrite => _inner.CanWrite; public override long Length => _inner.Length; public override long Position { get => _inner.Position; set => _inner.Position = value; } public override bool CanTimeout => _inner.CanTimeout; public override int ReadTimeout { get => _inner.ReadTimeout; set => _inner.ReadTimeout = value; } public override int WriteTimeout { get => _inner.WriteTimeout; set => _inner.WriteTimeout = value; } public ContentLengthTracker Tracker => _tracker; public override void Flush() => _inner.Flush(); public override Task FlushAsync(CancellationToken cancellationToken) => _inner.FlushAsync(cancellationToken); public override int Read(byte[] buffer, int offset, int count) => _inner.Read(buffer, offset, count); public async override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => await _inner.ReadAsync(buffer, offset, count, cancellationToken); public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => _inner.BeginRead(buffer, offset, count, callback, state); public override int EndRead(IAsyncResult asyncResult) { Task<int> task = asyncResult as Task<int>; if (task != null) { return task.GetAwaiter().GetResult(); } return _inner.EndRead(asyncResult); } public override long Seek(long offset, SeekOrigin origin) => _inner.Seek(offset, origin); public override void SetLength(long value) => _inner.SetLength(value); public override void Write(byte[] buffer, int offset, int count) { _tracker.ContentLength += count - offset; _inner.Write(buffer, offset, count); } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { // _tracker.ContentLength += count - offset; // This is incorrect _tracker.ContentLength += count; return _inner.BeginWrite(buffer, offset, count, callback, state); } public override void EndWrite(IAsyncResult asyncResult) => _inner.EndWrite(asyncResult); public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { // _tracker.ContentLength += count - offset; // This is incorrect _tracker.ContentLength += count; return _inner.WriteAsync(buffer, offset, count, cancellationToken); } public override void WriteByte(byte value) { _tracker.ContentLength++; _inner.WriteByte(value); } protected override void Dispose(bool disposing) { if (disposing) { _inner.Dispose(); } } }
我假設您正在嘗試從中間件中獲取 ContentLength ?
這是一個範例中間件。它應該在任何響應生成中間件(例如 useMVC 或 useStaticFiles)之前添加到管道 (startup.cs)。
public class ContentLengthMiddleware { RequestDelegate _next; public ContentLengthMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { using (var buffer = new MemoryStream()) { var request = context.Request; var response = context.Response; var bodyStream = response.Body; response.Body = buffer; await _next(context); Debug.WriteLine($"{request.Path} ({response.ContentType}) Content-Length: {response.ContentLength ?? buffer.Length}"); buffer.Position = 0; await buffer.CopyToAsync(bodyStream); } } }由於在返回靜態文件(png、js 等)時超出我理解的原因,響應正文將為空,但是設置了 ContentLength,這就是我使用
response.ContentLength ?? buffer.Length.(mod注意:對於兩個問題的重複答案感到抱歉。另一個答案發布不正確,打開的標籤太多。我將其刪除並在此處重新發布答案)。