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

.NET Maui Android中POST请求因URL含下划线抛出Java异常

.NET Maui Android 请求含下划线域名异常的解决方案

问题根源

Android平台的TLS SNI扩展在处理域名时,严格遵循STD3 ASCII规则,不允许域名包含下划线。当请求https://changed_for_privacy.com这类域名时,SNI握手阶段的IDNA解析会抛出Java.Lang.IllegalArgumentException异常,而Postman等工具因使用宽松解析策略可正常请求。

解决方案

方法一:自定义OkHttp客户端(推荐)

.NET Maui在Android底层依赖OkHttp,可通过配置OkHttp允许含下划线的域名:

  1. 给Android项目安装Square.OkHttp3 NuGet包
  2. 创建自定义HttpMessageHandler:
using OkHttp3;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace YourProject.Platforms.Android
{
    public class CustomOkHttpHandler : HttpMessageHandler
    {
        private readonly OkHttpClient _okHttpClient;

        public CustomOkHttpHandler()
        {
            var clientBuilder = new OkHttpClient.Builder()
                .Dns(Dns.Safe) // 使用宽松的DNS解析策略
                .Build();
            _okHttpClient = clientBuilder;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var okRequestBuilder = new Request.Builder().Url(request.RequestUri.ToString());

            // 复制请求方法和内容
            if (request.Content != null)
            {
                var contentBytes = await request.Content.ReadAsByteArrayAsync(cancellationToken);
                var mediaType = MediaType.Parse(request.Content.Headers.ContentType?.ToString());
                var okRequestBody = RequestBody.Create(contentBytes, mediaType);
                okRequestBuilder.Method(request.Method.Method, okRequestBody);
            }
            else
            {
                okRequestBuilder.Method(request.Method.Method, null);
            }

            // 复制请求头
            foreach (var header in request.Headers)
            {
                okRequestBuilder.AddHeader(header.Key, string.Join(", ", header.Value));
            }

            var okResponse = await _okHttpClient.NewCall(okRequestBuilder.Build()).ExecuteAsync(cancellationToken);

            // 转换为.NET HttpResponseMessage
            var response = new HttpResponseMessage((System.Net.HttpStatusCode)(int)okResponse.Code)
            {
                Content = new ByteArrayContent(await okResponse.Body.BytesAsync())
            };

            // 复制响应头
            foreach (var header in okResponse.Headers)
            {
                response.Headers.TryAddWithoutValidation(header.Key, string.Join(", ", header.Value));
            }

            return response;
        }
    }
}
  1. 修改HttpClient初始化逻辑,针对Android平台使用自定义Handler:
internal class MyService
{
    private readonly HttpClient httpClient;

    public MyService()
    {
#if ANDROID
        httpClient = new HttpClient(new YourProject.Platforms.Android.CustomOkHttpHandler());
#else
        httpClient = new HttpClient();
#endif
    }

    // 其余代码保持不变
}

方法二:禁用SNI(不推荐,有安全风险)

通过系统属性禁用SNI扩展,跳过域名格式检查,但会降低TLS连接的安全性:

在Android项目的MainApplication.cs中添加如下代码:

using Android.App;
using Android.Runtime;

namespace YourProject.Platforms.Android
{
    [Application]
    public class MainApplication : MauiApplication
    {
        public MainApplication(IntPtr handle, JniHandleOwnership ownership)
            : base(handle, ownership)
        {
        }

        protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();

        public override void OnCreate()
        {
            base.OnCreate();
            // 禁用SNI扩展
            System.Properties.SetProperty("jsse.enableSNIExtension", "false");
        }
    }
}

方法三:自定义主机名验证器

跳过特定含下划线域名的SNI验证:

  1. 创建自定义主机名验证器:
using Android.Net.Http;
using Java.Security.Cert;

namespace YourProject.Platforms.Android
{
    public class CustomHostnameVerifier : Java.Lang.Object, IHostnameVerifier
    {
        public bool Verify(string hostname, ISSLSession session)
        {
            // 允许目标域名,或保留默认验证逻辑
            return hostname.Equals("changed_for_privacy.com") 
                || HttpsURLConnection.DefaultHostnameVerifier.Verify(hostname, session);
        }
    }
}
  1. 修改HttpClient初始化:
internal class MyService
{
    private readonly HttpClient httpClient;

    public MyService()
    {
#if ANDROID
        var handler = new AndroidMessageHandler();
        handler.HostnameVerifier = new YourProject.Platforms.Android.CustomHostnameVerifier();
        httpClient = new HttpClient(handler);
#else
        httpClient = new HttpClient();
#endif
    }

    // 其余代码保持不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:08:10