You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RestSharp HTTP访问HTTPS端口触发TaskCanceledException问题排查

问题与解答:RestSharp 108.0.2 中的TaskCanceledException异常处理

问题背景

我正在为使用RestSharp(版本108.0.2)的REST应用构建错误处理逻辑。服务器设置为6543端口接收HTTP请求,3456端口接收HTTPS请求。当我使用http://myServer:3456访问时(预期会报错),却触发了TaskCanceledException,且CancellationToken.IsCancellationRequested为true,看起来像是用户手动触发了取消令牌,但实际并未操作。

想请教:

  1. 该异常产生的原因是什么?
  2. 如何获取更易懂的错误描述(面向非技术用户),或至少区分手动取消与协议错误,以便向用户展示准确提示?

客户端初始化代码

RestClientOptions options = new RestClientOptions()
{
    BaseUrl = new Uri(serviceUrl),
    PreAuthenticate = false,
    Timeout = cTimeout,
    UseDefaultCredentials = globalSettings.AuthMechanism != AuthMechanism.Basic,
    UserAgent = $"{Assembly.GetExecutingAssembly().GetName().Name}/{Assembly.GetExecutingAssembly().GetName().Version}"
};
RestClient = new RestClient(options);

请求代码

RestRequest request = new RestRequest($"{GlobalSettings.ApiSystemUrl}/info", Method.Get);
RestResponse result = await mRestClient.ExecuteAsync(request);

返回的原始JSON结果

{
    "Request":
    {
        "AlwaysMultipartFormData": false,
        "MultipartFormQuoteParameters": false,
        "FormBoundary": null,
        "Parameters": [],
        "Files": [],
        "Method": 0,
        "Timeout": 0,
        "Resource": "/api/v1/info",
        "RequestFormat": 0,
        "RootElement": null,
        "OnBeforeDeserialization": null,
        "OnBeforeRequest": null,
        "OnAfterRequest": null,
        "Attempts": 1,
        "CompletionOption": 0,
        "ResponseWriter": null,
        "AdvancedResponseWriter": null
    },
    "ContentType": null,
    "ContentLength": null,
    "ContentEncoding": [],
    "Content": null,
    "StatusCode": 0,
    "IsSuccessful": false,
    "StatusDescription": null,
    "RawBytes": null,
    "ResponseUri": null,
    "Server": null,
    "Cookies": null,
    "Headers": null,
    "ContentHeaders": null,
    "ResponseStatus": 4,
    "ErrorMessage": "Eine Aufgabe wurde abgebrochen.",
    "ErrorException":
    {
        "ClassName": "System.Threading.Tasks.TaskCanceledException",
        "Message": "Eine Aufgabe wurde abgebrochen.",
        "Data": null,
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   bei RestSharp.RestClient.<ExecuteInternal>d__1.MoveNext()",
        "RemoteStackTraceString": null,
        "RemoteStackIndex": 0,
        "ExceptionMethod": "8\nThrowForNonSuccess\nmscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.Runtime.CompilerServices.TaskAwaiter\nVoid ThrowForNonSuccess(System.Threading.Tasks.Task)",
        "HResult": -2146233029,
        "Source": "mscorlib",
        "WatsonBuckets": null
    },
    "Version": null,
    "RootElement": null
}

当前异常处理代码

if (!result.IsSuccessful)
....

if (result.ErrorException != null)
{
    if (result.ErrorException is TaskCanceledException cancel)
    {
        if (cancel.CancellationToken.IsCancellationRequested)
        {
            errorDescription += " " + RestClientStrings.Error_CanceledByUser;
        }
        else
        {
            errorDescription += " " + RestClientStrings.Error_CanceledByTimeout;
        }
    }
}

解答

1. 异常产生的原因

用HTTP协议访问HTTPS专属端口(3456)时,客户端与服务器无法完成协议握手,连接建立失败后触发请求超时,RestSharp内部会使用取消令牌终止任务,最终抛出TaskCanceledException。此时CancellationToken.IsCancellationRequested为true是RestSharp内部逻辑导致,并非用户手动操作。

2. 区分错误类型并生成友好提示

可以通过以下几种方式优化错误处理逻辑:

方式一:利用RestResponse的ResponseStatus枚举判断

RestSharp的RestResponse.ResponseStatus直接标记了请求失败的核心原因,优先判断这个值可以快速区分错误类型:

if (!result.IsSuccessful)
{
    switch(result.ResponseStatus)
    {
        case ResponseStatus.TimedOut:
            errorDescription = RestClientStrings.Error_CanceledByTimeout;
            break;
        case ResponseStatus.Error:
            // 结合请求地址判断是否是协议端口不匹配
            var targetUri = new Uri(serviceUrl);
            bool isProtocolPortMismatch = (targetUri.Scheme == "http" && targetUri.Port == 3456) || 
                                          (targetUri.Scheme == "https" && targetUri.Port == 6543);
            
            if (isProtocolPortMismatch)
            {
                errorDescription = "连接失败:请确认访问地址的协议与端口匹配(HTTP对应6543,HTTPS对应3456)";
            }
            else if (result.ErrorException is TaskCanceledException)
            {
                errorDescription = "连接失败:无法与服务器建立有效连接,请检查网络或服务器地址";
            }
            else
            {
                errorDescription = result.ErrorMessage ?? "未知请求错误";
            }
            break;
        case ResponseStatus.Canceled:
            errorDescription = RestClientStrings.Error_CanceledByUser;
            break;
        default:
            errorDescription = $"请求失败:{result.StatusDescription ?? "未知原因"}";
            break;
    }
}

方式二:传入自定义取消令牌区分用户手动取消

如果需要支持用户手动取消请求,建议使用自定义的CancellationTokenSource,通过它的令牌来区分用户操作和内部取消:

// 定义全局或请求级别的用户取消令牌源
private CancellationTokenSource _userCancelTokenSource = new CancellationTokenSource();

// 请求时传入自定义令牌
RestResponse result = await mRestClient.ExecuteAsync(request, _userCancelTokenSource.Token);

// 异常处理时
if (result.ErrorException is TaskCanceledException)
{
    if (_userCancelTokenSource.Token.IsCancellationRequested)
    {
        errorDescription = RestClientStrings.Error_CanceledByUser;
    }
    else
    {
        // 内部取消,属于超时或连接错误
        errorDescription = "请求超时或连接失败,请检查网络配置";
    }
}

方式三:提前验证协议与端口匹配性

在发起请求前提前检查URL的协议和端口是否符合服务器规则,直接拦截这类错误:

var requestUri = new Uri(serviceUrl);
bool isValidPortForScheme = (requestUri.Scheme == "http" && requestUri.Port == 6543) || 
                            (requestUri.Scheme == "https" && requestUri.Port == 3456);

if (!isValidPortForScheme)
{
    errorDescription = "地址错误:HTTP请求需使用6543端口,HTTPS请求需使用3456端口";
    return;
}

// 后续正常发起请求
RestRequest request = new RestRequest($"{GlobalSettings.ApiSystemUrl}/info", Method.Get);
RestResponse result = await mRestClient.ExecuteAsync(request);

内容的提问来源于stack exchange,提问作者Marcel Grüger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:45:34