WebApi 请求中的取消
Cancellation in WebApi requests
关于使用 CancellationTokens 取消 WebApi 请求的资源有多种,例如(这个概念似乎适用于所有最新版本):
- https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/
- https://www.davepaquette.com/archive/2015/07/19/cancelling-long-running-queries-in-asp-net-mvc-and-web-api.aspx
现在我还了解到,通常对于 HTTP 连接,您不会在每次发送新请求时打开和关闭 TCP 连接,但通常会让 TCP 连接保持打开状态,至少我是这样理解这篇文章的MDN:A typical HTTP session.
所以我的问题是:
如果我从 C# 发出 HTTP 请求,是否每次都会建立和关闭底层 TCP 连接,以便该机制基本上是关闭 TCP 连接并且服务器可以请求令牌中的取消?
所以这最终是否依赖于我总是为每个请求打开一个新的 TCP 连接这一事实?或者在 TCP 连接不会关闭的情况下是否还有其他东西(也)可以工作?
这是 Github.
中 HttpWebrequest.Abort() 方法的源代码
private void Abort(Exception exception, int abortState)
{
GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort()");
if (Logging.On) Logging.Enter(Logging.Web, this, "Abort", (exception == null? "" : exception.Message));
if(Interlocked.CompareExchange(ref m_Aborted, abortState, 0) == 0) // public abort will never drain streams
{
GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort() - " + exception);
NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.HttpWebRequestAborted);
m_OnceFailed = true;
CancelTimer();
WebException webException = exception as WebException;
if (exception == null)
{
webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
}
else if (webException == null)
{
webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), exception, WebExceptionStatus.RequestCanceled, _HttpResponse);
}
try
{
// Want to make sure that other threads see that we're aborted before they set an abort delegate, or that we see
// the delegate if they might have missed that we're aborted.
Thread.MemoryBarrier();
HttpAbortDelegate abortDelegate = _AbortDelegate;
if (abortDelegate == null || abortDelegate(this, webException))
{
// We don't have a connection associated with this request
SetResponse(webException);
}
else
{
// In case we don't call SetResponse(), make sure to complete the lazy async result
// objects. abortDelegate() may not end up in a code path that would complete these
// objects.
LazyAsyncResult writeAResult = null;
LazyAsyncResult readAResult = null;
if (!Async)
{
lock (this)
{
writeAResult = _WriteAResult;
readAResult = _ReadAResult;
}
}
if (writeAResult != null)
writeAResult.InvokeCallback(webException);
if (readAResult != null)
readAResult.InvokeCallback(webException);
}
if (!Async)
{
LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult;
LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;
if (chkConnectionAsyncResult != null)
chkConnectionAsyncResult.InvokeCallback(webException);
if (chkReaderAsyncResult != null)
chkReaderAsyncResult.InvokeCallback(webException);
}
if (this.IsWebSocketRequest && this.ServicePoint != null)
{
this.ServicePoint.CloseConnectionGroup(this.ConnectionGroupName);
}
}
catch (InternalException)
{
}
}
if(Logging.On)Logging.Exit(Logging.Web, this, "Abort", "");
}
这清楚地表明 TCP 连接正在关闭。服务器以自己的方式响应关闭的 TCP 端口。
link : https://serverfault.com/questions/147886/what-happens-when-a-http-request-is-terminated-prematurely
在 HTTP 请求-响应交换之后,您无需担心连接是否关闭,因为它对取消机制没有影响。确实有影响的是,在 HTTP 请求-响应交换期间关闭连接,因为这会触发取消服务器端的请求处理,以防它处理取消令牌。所以换句话说,如果连接在发送响应之前关闭,无论连接是什么类型(保持活动或每次交换),这都是服务器启动取消过程的原因。
关于使用 CancellationTokens 取消 WebApi 请求的资源有多种,例如(这个概念似乎适用于所有最新版本):
- https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/
- https://www.davepaquette.com/archive/2015/07/19/cancelling-long-running-queries-in-asp-net-mvc-and-web-api.aspx
现在我还了解到,通常对于 HTTP 连接,您不会在每次发送新请求时打开和关闭 TCP 连接,但通常会让 TCP 连接保持打开状态,至少我是这样理解这篇文章的MDN:A typical HTTP session.
所以我的问题是:
如果我从 C# 发出 HTTP 请求,是否每次都会建立和关闭底层 TCP 连接,以便该机制基本上是关闭 TCP 连接并且服务器可以请求令牌中的取消?
所以这最终是否依赖于我总是为每个请求打开一个新的 TCP 连接这一事实?或者在 TCP 连接不会关闭的情况下是否还有其他东西(也)可以工作?
这是 Github.
中 HttpWebrequest.Abort() 方法的源代码 private void Abort(Exception exception, int abortState)
{
GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort()");
if (Logging.On) Logging.Enter(Logging.Web, this, "Abort", (exception == null? "" : exception.Message));
if(Interlocked.CompareExchange(ref m_Aborted, abortState, 0) == 0) // public abort will never drain streams
{
GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort() - " + exception);
NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.HttpWebRequestAborted);
m_OnceFailed = true;
CancelTimer();
WebException webException = exception as WebException;
if (exception == null)
{
webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
}
else if (webException == null)
{
webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), exception, WebExceptionStatus.RequestCanceled, _HttpResponse);
}
try
{
// Want to make sure that other threads see that we're aborted before they set an abort delegate, or that we see
// the delegate if they might have missed that we're aborted.
Thread.MemoryBarrier();
HttpAbortDelegate abortDelegate = _AbortDelegate;
if (abortDelegate == null || abortDelegate(this, webException))
{
// We don't have a connection associated with this request
SetResponse(webException);
}
else
{
// In case we don't call SetResponse(), make sure to complete the lazy async result
// objects. abortDelegate() may not end up in a code path that would complete these
// objects.
LazyAsyncResult writeAResult = null;
LazyAsyncResult readAResult = null;
if (!Async)
{
lock (this)
{
writeAResult = _WriteAResult;
readAResult = _ReadAResult;
}
}
if (writeAResult != null)
writeAResult.InvokeCallback(webException);
if (readAResult != null)
readAResult.InvokeCallback(webException);
}
if (!Async)
{
LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult;
LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;
if (chkConnectionAsyncResult != null)
chkConnectionAsyncResult.InvokeCallback(webException);
if (chkReaderAsyncResult != null)
chkReaderAsyncResult.InvokeCallback(webException);
}
if (this.IsWebSocketRequest && this.ServicePoint != null)
{
this.ServicePoint.CloseConnectionGroup(this.ConnectionGroupName);
}
}
catch (InternalException)
{
}
}
if(Logging.On)Logging.Exit(Logging.Web, this, "Abort", "");
}
这清楚地表明 TCP 连接正在关闭。服务器以自己的方式响应关闭的 TCP 端口。 link : https://serverfault.com/questions/147886/what-happens-when-a-http-request-is-terminated-prematurely
在 HTTP 请求-响应交换之后,您无需担心连接是否关闭,因为它对取消机制没有影响。确实有影响的是,在 HTTP 请求-响应交换期间关闭连接,因为这会触发取消服务器端的请求处理,以防它处理取消令牌。所以换句话说,如果连接在发送响应之前关闭,无论连接是什么类型(保持活动或每次交换),这都是服务器启动取消过程的原因。