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

Xamarin使用HttpClient调用.Net Core Web API超时设置不生效求助

问题根因

你之前的超时方案未生效主要有3个核心原因:

  • 即使启用了CancellationTokenSource.CancelAfter,也没有将取消令牌传入PostAsync方法,超时触发时无法终止请求
  • 调用response.Content.ReadAsStringAsync().Result使用同步阻塞方式读取响应,极易造成线程死锁,导致超时逻辑无法正常触发
  • 每次请求都新建HttpClient实例,不仅会导致socket资源泄漏,也可能让部分平台下的Timeout配置不生效

修正方案

第一步:调整HttpClient为单例模式

在你的API调用类中定义静态HttpClient实例,全局复用:

// 类级别静态变量,不要每次请求新建
private static readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler{AllowAutoRedirect = true})
{
    Timeout = TimeSpan.FromSeconds(10) // 全局默认超时时间
};

第二步:改造Post方法,正确使用取消令牌+异步读取响应

修改后的完整Post方法如下:

public async Task<BaseResponseModel> Post(BasePostModel postModel)
{
    var responseModel = new BaseResponseModel();
    var isPosted = true;
    var url = GetURL(postModel.UrlKey);

    var settings = new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore,
        MissingMemberHandling = MissingMemberHandling.Ignore,
        ContractResolver = new DefaultContractResolver(),
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };

    // 可选:提前判断网络状态,无网直接返回错误(依赖Xamarin.Essentials)
    if (Connectivity.NetworkAccess != NetworkAccess.Internet)
    {
        responseModel.Error = "网络异常,请检查您的网络设置";
        responseModel.Message = "网络异常,请检查您的网络设置";
        return responseModel;
    }

    // 初始化取消令牌,10秒超时
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));

    try
    {
        // 配置请求头
        _httpClient.DefaultRequestHeaders.Clear();
        _httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
        _httpClient.DefaultRequestHeaders.Add("X-Env", "MOBILE_API");
        AttachToken(ref _httpClient, responseModel.Id);

        var json = postModel.ToString();
        var jsonParam = new StringContent(json, Encoding.UTF8, "application/json");

        // 统一处理Token过期逻辑
        if (Preferences.ContainsKey("UserJwtExprieDate"))
        {
            var expiryDate = Preferences.Get("UserJwtExprieDate", null);
            if (DateTime.Now > DateTime.Parse(expiryDate))
            {
                Preferences.Remove("UserJwtExprieDate");
                Preferences.Remove("HomePageInformation");
                int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
                Page currPage = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
                if (currPage as SigninForFactorOne == null)
                {
                    App.LogoutUser();
                }
                responseModel.Error = "登录已过期,请重新登录";
                responseModel.Message = "登录已过期,请重新登录";
                return responseModel;
            }
        }

        // 传入取消令牌,超时自动终止请求
        var response = await _httpClient.PostAsync(url, jsonParam, cts.Token);
        if (response.IsSuccessStatusCode)
        {
            // 改用await异步读取,避免线程死锁
            string result = await response.Content.ReadAsStringAsync();
            var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
            if (resultModel.ErrorType == APIErrorTypes.NULL)
            {
                if (resultModel.IsSucceed)
                {
                    responseModel.Data = resultModel.Data;
                }
                else
                {
                    responseModel.Error = resultModel.Error;
                }
                responseModel.Message = resultModel.Message;
            }
            else
            {
                responseModel.Error = "登录已过期,请重新登录";
                Preferences.Remove("UserJwtExprieDate");
                Preferences.Remove("HomePageInformation");
                App.LogoutUser();
            }
        }
        else
        {
            new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
            isPosted = false;
        }
    }
    // 单独捕获超时异常,自定义提示
    catch (OperationCanceledException)
    {
        isPosted = false;
        responseModel.Error = "请求超时,请检查网络后重试";
        responseModel.Message = "请求超时,请检查网络后重试";
    }
    catch (Exception ex)
    {
        new AppException(ex, responseModel.Id, 500, "anonymous.user", "Unable to post data to API!");
        isPosted = false;
    }
    finally
    {
        if (!isPosted && string.IsNullOrEmpty(responseModel.Error))
        {
            responseModel.Error = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
            responseModel.Message = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
        }
    }

    return responseModel;
}

额外注意点

  • 调用该Post方法的上层代码不要用.Result或者.Wait()阻塞,全程用await异步调用,避免UI线程死锁
  • 上层业务代码拿到返回的responseModel后,判断Error字段不为空时,即可关闭加载动画、弹出对应的用户提示

内容的提问来源于stack exchange,提问作者mkartal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 15:45:02