为了提供一些上下文,我正在执行一个 HTTP 请求,其响应预计是一个流。因此,我在从
StreamReader
返回的流之上使用 HttpResponseMessage
。
最简单的场景
using ( var streamReader = new StreamReader( await httpClient.GetStreamAsync( url, ct ) ) )
{
while ( !streamReader.EndOfStream && !ct.IsCancellationRequested )
{
var line = await streamReader.ReadLineAsync( ct );
Console.WriteLine( line );
}
}
所以现在的情况是我有一个超时
CancellationToken
,但是当请求取消时,它不会执行任何操作。 ReadLineAsync
“卡住”是很常见的,因为只有在有新内容时才会传输数据。但因为网络问题不会影响直播,所以我在过了一定时间后添加了取消请求。
再次,最简单的场景
CancellationTokenSource cts = new CancellationTokenSource();
var ct = cts.Token;
ct.Register( () =>
{
logger.LogInformation( "Cancellation requested." );
} );
运行应用程序,我可以看到请求取消
2023-05-03 06:29:10 info: consoleapp[0] Cancellation requested.
但读者不为所动。
所以我继续查看底层流类型是什么,它是一个
HttpConnection.ConnectionCloseReadStream
。来源可以在这里找到。
看代码,调用
HttpConnection.ReadAsync
方法时似乎没有使用取消令牌。
ValueTask<int> readTask = connection.ReadAsync(buffer);
不确定这是否重要,因为最重要的是我们有
CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
但现实是,它并没有真正发挥作用。
有人对此有任何见解吗?
在您提供的示例(SocketsHttpHandler 的 HttpConnection)中,必须将 CancellationToken 传递到执行管道才能使取消正常工作,并且该区域有一些修复。 (例如 https://github.com/dotnet/corefx/pull/40715,https://github.com/dotnet/runtime/pull/686)
特别是在 HttpConnection 中,他们还使用 CancellationTokens 注册操作来拆除连接(在某些情况下,可以免除将令牌进一步传递到执行管道)