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

Android低于KitKat版本时HttpUrlConnection忽略代理问题

AndroidClientHandler Proxy Support on JellyBean (API 16-18)

First off, the short answer: AndroidClientHandler does NOT have proper proxy support for JellyBean (API 16 to 18). This is a well-documented limitation in the Xamarin.Android implementation prior to Lollipop (API 21), and it’s exactly why your requests aren’t routing through the proxy on older devices.

Why This Happens

The core issue lies in how AndroidClientHandler manages socket connections pre-API 21. On KitKat (API 19) and above, a partial fix added support for passing proxy configuration to the underlying socket logic, but JellyBean builds completely lack this handling. When you send an HTTP/HTTPS request, the handler ignores your proxy settings entirely and connects directly to the target server.

Since you’re already subclassing AndroidClientHandler to bypass SSL validation (which makes perfect sense here, since your proxy handles SSL termination), you can extend this subclass to manually add proxy support for JellyBean devices.

Fix: Manually Implement Proxy Logic in Your Custom Handler

Here’s how you can modify your subclass to force proxy routing on JellyBean devices:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Android.OS;
using Xamarin.Android.Net;

public class ProxyEnabledAndroidHandler : AndroidClientHandler
{
    private readonly IWebProxy _targetProxy;

    public ProxyEnabledAndroidHandler(IWebProxy proxy)
    {
        _targetProxy = proxy;
        // Your existing SSL bypass logic (as required by your library)
        ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => true;
    }

    protected override async Task<Stream> GetStreamAsync(HttpWebRequest request, CancellationToken cancellationToken)
    {
        // Ensure the request uses our proxy
        if (_targetProxy != null && request.Proxy == null)
        {
            request.Proxy = _targetProxy;
        }

        // Special handling for JellyBean and older
        if (Build.VERSION.SdkInt <= BuildVersionCodes.JellyBeanMr2)
        {
            var proxyUri = _targetProxy.GetProxy(request.RequestUri);
            if (proxyUri != null && proxyUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase))
            {
                // Connect to the proxy server directly
                using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                await socket.ConnectAsync(proxyUri.Host, proxyUri.Port).ConfigureAwait(false);

                // Send CONNECT request to establish tunnel to target server
                var connectCommand = $"CONNECT {request.RequestUri.Host}:{request.RequestUri.Port} HTTP/1.1\r\nHost: {request.RequestUri.Host}:{request.RequestUri.Port}\r\n\r\n";
                var connectBytes = Encoding.ASCII.GetBytes(connectCommand);
                await socket.SendAsync(connectBytes, SocketFlags.None).ConfigureAwait(false);

                // Verify proxy accepted the connection
                var responseBuffer = new byte[1024];
                var bytesRead = await socket.ReceiveAsync(responseBuffer, SocketFlags.None).ConfigureAwait(false);
                var proxyResponse = Encoding.ASCII.GetString(responseBuffer, 0, bytesRead);
                
                if (!proxyResponse.StartsWith("HTTP/1.1 200", StringComparison.OrdinalIgnoreCase))
                {
                    throw new IOException($"Proxy connection failed: {proxyResponse.Trim()}");
                }

                // Return the tunneled stream for the request to use
                return new NetworkStream(socket, true);
            }
        }

        // For newer versions, use the base handler's native logic
        return await base.GetStreamAsync(request, cancellationToken).ConfigureAwait(false);
    }
}

Key Notes

  • This code manually creates a tunnel through the proxy using the HTTP CONNECT method, which works for both HTTPS and HTTP requests.
  • Since your proxy handles SSL termination, bypassing client-side SSL validation is appropriate here—just ensure you fully trust the proxy you’re working with.
  • If you only need to handle HTTP (not HTTPS) requests, you can simplify the logic by sending the full request directly to the proxy instead of using the CONNECT method.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:10:29