Mil*_*kic 6 .net asp.net http asp.net-core-mvc asp.net-core
TL; DR我有一个 ASP.NET 5 (MVC 6) 应用程序,只是尝试设置 HTTP Content-Length 标头以避免分块响应。
令我惊讶的是,这在 ASP.NET 5 中是一项相当棘手的任务。一切都在 Kestrel 上运行,从 ASP.NET 5 Beta7 开始,当没有为响应指定内容长度时,它支持自动写入分块响应。
这里有一个类似的问题,但不同之处在于OP只想计算响应大小,而我需要确保Content-Length标头在响应中发送。到目前为止尝试了很多事情,唯一有效的是编写一个自定义中间件:
public class WebApiMiddleware {
RequestDelegate _next;
public WebApiMiddleware(RequestDelegate next) {
_next = next;
}
public async Task Invoke(HttpContext context) {
using (var buffer = new MemoryStream()) {
var response = context.Response;
var bodyStream = response.Body;
response.Body = buffer;
await _next(context);
response.Headers.Add("Content-Length", new[] { buffer.Length.ToString()});
buffer.Position = 0;
await buffer.CopyToAsync(bodyStream);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这是非常低效的,因为我们在处理每个请求时都使用额外的内存。使用仅环绕流context.Response.Body并另外计算字节的自定义流是行不通的,因为 Microsoft 团队声明,一旦写入了他们愿意缓冲的数据量,数据就会通过网络传输,而他们不会不再存储它,所以我最多可以将 Content-Length 添加到最后一个块,这不是期望的行为 - 我想完全避免分块。
非常感谢任何帮助!
ps 我知道分块是 HTTP/1.1 的常规功能,但在我的场景中它会降低性能,因此我想避免它而不强制客户端发送 HTTP/1.0 请求。
您需要在发送响应之前发送标头,因此您需要在发送之前存储整个响应以确定长度。
正如您所说,context.Response.Body流在发送之前不会存储太多,因此开销并没有那么大。
有一个中间件可以做类似的事情: https: //github.com/aspnet/BasicMiddleware/blob/master/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs它与您编写的非常相似,但支持其他功能,例如IHttpBufferingFeature允许其他中间件控制缓冲。
检查bufferStream.CanSeek是为了确保没有人已经将响应流包装到缓冲流中并避免双缓冲。
对于你的第二个问题:这个地方是中间件。
| 归档时间: |
|
| 查看次数: |
11544 次 |
| 最近记录: |