【问题标题】:Xamarin Forms WebView ProxyXamarin 窗体 WebView 代理
【发布时间】:2017-06-22 21:52:42
【问题描述】:

如何让 iOS 和 Android 强制所有 http/s 请求通过代理?本地化到应用程序,而不是整个操作系统?

我在 Android 上试过这个,但对 Https 不起作用:

JavaSystem.setProperty("http.proxyHost", <your proxy host name>);
JavaSystem.setProperty("http.proxyPort", <your proxy port>);
JavaSystem.setProperty("https.proxyHost", <your proxy host name>);
JavaSystem.setProperty("https.proxyPort", <your proxy port>);

对于 Android,我也尝试过实现 WebClient 并覆盖 shouldoverrideurlloading 但 Xamarin 似乎在 HttpWebRequest 和 https 调用方面存在问题,抱怨

Error: SecureChannelFailure (The authentication or decryption has failed.)"

【问题讨论】:

  • 你能解释一下你的场景吗?如果您希望将其本地化为应用程序而不是系统,您不能在任何地方编写一个包装函数吗?

标签: c# android xamarin proxy xamarin.forms


【解决方案1】:

不幸的是,重写 WebClient shouldInterceptRequest 有一些问题,例如拦截 html 以外的任何内容,但我设法通过这种方式解决了我的问题:

public class DawgWebViewClient: WebViewClient
{
    private class DawgWebResourceResponse : WebResourceResponse
    {
        IWebResourceRequest baseRequest;
        public DawgWebResourceResponse(IWebResourceRequest request) : base(null, null, null)
        {
            this.baseRequest = request;
            this.LoadRequestAsync();
        }

        ManualResetEvent responseDataWaiter = new ManualResetEvent(false);
        ManualResetEvent metaDataWaiter = new ManualResetEvent(false);
        private void LoadRequestAsync()
        {
            Task.Run(async () =>
            {
                HttpClient client = new HttpClient(new ModernHttpClient.NativeMessageHandler());
                foreach(var header in this.baseRequest.RequestHeaders)
                {
                    client.DefaultRequestHeaders.Add(header.Key, header.Value);
                }

                HttpResponseMessage response;
                switch(this.baseRequest.Method)
                {
                    case "GET":
                        response = await client.GetAsync(this.baseRequest.Url.ToString());
                        break;
                    default:
                        response = null;
                        Debugger.Break();
                        break;
                }

                string
                    mediaType = response.Content.Headers.ContentType?.MediaType ?? "*/*",
                    charSet = response.Content.Headers.ContentType?.CharSet ?? "UTF-8";

                this.MimeType = mediaType;
                this._statusCode = (int)response.StatusCode;
                this.ResponseHeaders = response.Headers.ToDictionary(y => y.Key, y => y.Value.FirstOrDefault());
                metaDataWaiter.Set();

                this.Data = await response.Content.ReadAsStreamAsync();

                responseDataWaiter.Set();
            });
        }

        public override Stream Data
        {
            get {
                this.responseDataWaiter.WaitOne();
                return base.Data;
            }
            set
            {
                base.Data = value;
            }
        }

        public override IDictionary<string, string> ResponseHeaders
        {
            get
            {
                this.metaDataWaiter.WaitOne();
                return base.ResponseHeaders;
            }
            set
            {
                base.ResponseHeaders = value;
            }
        }

        private int _statusCode = 0;
        public override int StatusCode
        {
            get
            {
                this.metaDataWaiter.WaitOne();
                return this._statusCode;
            }
        }
        public override string Encoding
        {
            get
            {
                this.metaDataWaiter.WaitOne();
                return base.Encoding;
            }
            set
            {
                base.Encoding = value;
            }
        }

        public override string ReasonPhrase
        {
            get
            {
                this.metaDataWaiter.WaitOne();
                return base.ReasonPhrase;
            }
        }

        public override string MimeType
        {
            get
            {
                this.metaDataWaiter.WaitOne();
                return base.MimeType;
            }
            set
            {
                base.MimeType = value;
            }
        }
    }

    public override WebResourceResponse ShouldInterceptRequest(Android.Webkit.WebView view, IWebResourceRequest request)
    {
        if(request.RequestHeaders["Accept"]?.Contains("text/html") == true) return new DawgWebResourceResponse(request);
        return null;
    }
}

【讨论】:

    【解决方案2】:

    我认为一个简单的方法是使用RestSharp library

    那么就可以使用下面的代码了:

    var client = new RestClient("http://example.com")
    client.Proxy = new WebProxy("http://proxy.example.com")
    

    如果您向不同的服务器发出请求,我认为您可以创建一个没有域的RestClient,然后使用RestRequest 指定完整的请求url。这个客户端可以是静态的,也可以是单例的。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2021-12-28
      • 2017-04-05
      • 2018-08-12
      • 2019-08-25
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多