如何检索当前的响应主体长度?
How to retrieve the current response body length?
我需要检索响应正文长度。
当我看https://github.com/aspnet/HttpAbstractions/wiki/Rolling-Notes-Response-Stream-Contract时说:
Stream.Position {get} and Stream.Length {get} return cumulative bytes written
这正是我需要的,但是 httpContext.Response.Body.Length
提高了 NotSupportedException
并说 "The stream is not seekable."
我应该使用委托流来计算每次写入的字节数吗?
我假设您正在尝试从中间件中获取 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:对于两个问题的重复回答感到抱歉。另一个答案发布不正确,打开了太多选项卡。我删除了它并在此处重新发布了答案)。
这是在流写入期间跟踪内容长度的代码。
ContentLengthTracker
class 用于在其他 class 之间共享内容长度值。
代码发布于 https://github.com/ycrumeyrolle/Throttling/blob/master/src/Throttling/Internal/ContentLengthTrackingStream.cs
using 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();
}
}
}
我需要检索响应正文长度。
当我看https://github.com/aspnet/HttpAbstractions/wiki/Rolling-Notes-Response-Stream-Contract时说:
Stream.Position {get} and Stream.Length {get} return cumulative bytes written
这正是我需要的,但是 httpContext.Response.Body.Length
提高了 NotSupportedException
并说 "The stream is not seekable."
我应该使用委托流来计算每次写入的字节数吗?
我假设您正在尝试从中间件中获取 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:对于两个问题的重复回答感到抱歉。另一个答案发布不正确,打开了太多选项卡。我删除了它并在此处重新发布了答案)。
这是在流写入期间跟踪内容长度的代码。
ContentLengthTracker
class 用于在其他 class 之间共享内容长度值。
代码发布于 https://github.com/ycrumeyrolle/Throttling/blob/master/src/Throttling/Internal/ContentLengthTrackingStream.cs
using 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();
}
}
}