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

Xamarin.Forms中HttpClient请求抛出“发送请求时发生错误”问题排查求助

解决Xamarin.Forms中HttpClient调用内网ERP WebService的证书与认证问题

嘿,你碰到的这个问题其实是跨平台下HttpClient和WebRequest体系差异的典型坑——老WebRequest的证书验证设置没法直接复用给HttpClient,而且你的Basic认证格式可能也有问题。我来一步步帮你捋清楚:

核心问题拆解

你之前用ServicePointManager.ServerCertificateValidationCallback绕过证书验证的方式只对WebRequest生效,HttpClient有自己独立的请求处理链,在Xamarin的Android和UWP平台上不会自动继承这个设置。而先调用WebRequest再用HttpClient能工作,只是碰巧复用了WebRequest创建的ServicePoint,这完全是不可靠的跨平台解决方案。另外,你的Basic认证头构造不符合标准规范,这也会导致请求被拒绝。

解决方案步骤

1. 用自定义HttpClientHandler处理证书验证

别再依赖ServicePointManager了,直接给HttpClient配置专属的HttpClientHandler,它才是负责底层请求(包括证书验证)的核心组件:

public RestService() {
    // 修复Basic认证格式:标准要求是「用户名:密码」整体做Base64编码
    // 还原你原逻辑里的用户信息格式
    var rawCredential = $"{user.Replace("%CP1252%", "")}:{pswd}";
    // 用你指定的CP1252编码处理
    var credentialBytes = Encoding.GetEncoding("CP1252").GetBytes(rawCredential);
    var encodedAuth = Convert.ToBase64String(credentialBytes);

    // 创建自定义Handler,专门处理证书验证
    var httpHandler = new HttpClientHandler();
    httpHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => {
        // 注意:生产环境别直接返回true,建议验证证书的颁发者、有效期等信息
        // 这里先暂时绕过测试
        return true;
    };

    // 用这个Handler实例化HttpClient
    client = new HttpClient(httpHandler);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedAuth);
    
    // 强制使用安全TLS协议
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}

2. 修正异步请求的写法

你的GetDatas方法可以简化,同时确保异步流程正确(别用Wait(),避免死锁):

public async Task<string> GetDatas(string url) {
    var uri = new Uri(url);
    try {
        var response = await client.GetAsync(uri);
        // 主动检查请求状态,失败时抛出异常便于排查
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    } catch (HttpRequestException e) {
        Console.WriteLine($"请求失败: {e.Message}");
        if (e.InnerException != null) {
            Console.WriteLine($"内部错误详情: {e.InnerException.Message}");
        }
        return string.Empty;
    }
}

3. 平台特定配置

  • Android平台:

    • 在AndroidManifest.xml中添加网络权限:
      <uses-permission android:name="android.permission.INTERNET" />
      
    • 如果ERP用的是自签名证书或HTTP协议(Android 9+默认禁止明文流量),需要在Resources/xml下创建network_security_config.xml:
      <?xml version="1.0" encoding="utf-8"?>
      <network-security-config>
          <domain-config cleartextTrafficPermitted="true">
              <domain includeSubdomains="true">srverp</domain>
          </domain-config>
      </network-security-config>
      
      然后在AndroidManifest.xml的application标签中引用:
      android:networkSecurityConfig="@xml/network_security_config"
      
  • UWP平台:

    • 在Package.appxmanifest中开启内网访问权限:勾选Private Networks (Client & Server)
    • 如果是自签名证书,需要将证书导入到UWP项目的证书存储中,或者在代码中额外处理信任逻辑。

4. 移除冗余的WebRequest调用

现在你可以直接调用HttpClient方法,不需要依赖WebRequest的"预热"了:

public async Task<IEnumerable<Operation>> GetItemsAsync(bool forceRefresh = false) {
    await GetOperationsAsync(); // 直接调用HttpClient方法
    return Operations;
}

为什么之前的临时方法能工作?

当你先调用WebRequest时,它会创建一个ServicePoint并应用你设置的证书验证回调,HttpClient在某些情况下会复用这个ServicePoint,所以请求能成功。但跨平台下这种复用行为完全不可预测,尤其是在Android上,所以必须给HttpClient单独配置Handler才是可靠方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:43:11