首页 > 解决方案 > HTTPS 请求的 Xamarin 表单问题

问题描述

我使用Visual Studio 2017 ProfessionalVisual Studio 2019 累积版在Xamarin 表单中创建了一个应用程序。

问题是该应用程序可以很好地处理 HTTP 请求,但在HTTPS请求的情况下,我每次使用Visual Studio 2017和使用Visual Studio 2019时都会超时,我观察到有时会收到请求的响应,有时应用程序无法点击HTTPS请求。

我有相同的代码来调用 API。我每次都能成功地使用Postman发布WEB API 。

            HttpStatusCode = HttpStatusCode.Unused;
            HttpStatusCodeDescription = String.Empty;

            var response = default(TResp);
            XStatusCode = null;
            
            HttpWebRequest webRequest = null;
            HttpWebResponse webResponse = null;

            webRequest = (HttpWebRequest)WebRequest.Create(mServiceUrl + serviceName);
           
            webRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(userName + ":" + password)));
           
            webRequest.Method = "POST";

           

            var reqData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request));

            webRequest.ContentLength = reqData.Length;
            webRequest.ContentType = "application/json; charset=utf-8";
             using (var reqStream = webRequest.GetRequestStream())
                reqStream.Write(reqData, 0, reqData.Length);

            try
            {
                using (webResponse = (HttpWebResponse)webRequest.GetResponse())
                {
                    if (typeof(TResp) != typeof(object))
                    {
                        using (var respStream = webResponse.GetResponseStream())
                        {
                            var reader = new StreamReader(respStream);
                            string result = reader.ReadToEnd();
                            response = JsonConvert.DeserializeObject<TResp>(result);
                        }
                    }

                    HttpStatusCode = webResponse.StatusCode;
                    HttpStatusCodeDescription = webResponse.StatusDescription;
                }
            }
            catch (WebException ex)
            {
                webResponse = (HttpWebResponse)ex.Response;
                if (webResponse != null)
                {
                    HttpStatusCode = ((HttpWebResponse)webResponse).StatusCode;
                    HttpStatusCodeDescription = ((HttpWebResponse)webResponse).StatusDescription;
                    if (webResponse.Headers["X-StatusCode"] != null)
                    {
                        XStatusCode = int.Parse(webResponse.Headers["X-StatusCode"]);
                        if (webResponse.ContentLength > 0)
                        {
                            if (typeof(TResp) != typeof(object))
                            {
                                using (var respStream = webResponse.GetResponseStream())
                                {
                                    var reader = new StreamReader(respStream);
                                    string result = reader.ReadToEnd();
                                    response = JsonConvert.DeserializeObject<TResp>(result);
                                }
                            }
                        }
                    }
                    webResponse.Close();
                }
            }
           
            return response;

尝试使用 Http Client 也得到相同的结果

HttpStatusCode = HttpStatusCode.Unused;
            HttpStatusCodeDescription = String.Empty;

            var result = default(TResp);
            XStatusCode = null;
           



            try
            {
                var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(userName + ":" + password)));

                var json = JsonConvert.SerializeObject(request);
                HttpContent content = new StringContent(json);
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                var response = await client.PostAsync(mServiceUrl + serviceName, content);
              

                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<TResp>(response.Content.ToString());
                }

            }
            catch (WebException ex)
            {
                var webResponse = (HttpWebResponse)ex.Response;
                if (webResponse != null)
                {
                    HttpStatusCode = ((HttpWebResponse)webResponse).StatusCode;
                    HttpStatusCodeDescription = ((HttpWebResponse)webResponse).StatusDescription;
                    if (webResponse.Headers["X-StatusCode"] != null)
                    {
                        XStatusCode = int.Parse(webResponse.Headers["X-StatusCode"]);
                        if (webResponse.ContentLength > 0)
                        {
                            if (typeof(TResp) != typeof(object))
                            {
                                using (var respStream = webResponse.GetResponseStream())
                                {
                                    var reader = new StreamReader(respStream);
                                    string resulttmp = reader.ReadToEnd();
                                    result = JsonConvert.DeserializeObject<TResp>(resulttmp);
                                }
                            }
                        }
                    }
                    webResponse.Close();
                }
            }
            


            return result;

PCL 包是:- PCL Nuget 包
Android 安装包

添加以下行后

 System.Net.ServicePointManager.CheckCertificateRevocationList = true;

发布请求工作正常,但获取请求仍然存在问题

using (var client = new HttpClient())
            {
                try
                {

                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(userName + ":" + password)));
                    System.Net.ServicePointManager.DnsRefreshTimeout = 0;
                    System.Net.ServicePointManager.CheckCertificateRevocationList = true;
                    string url = mServiceUrl + serviceName;
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


                    var response = await client.GetStringAsync(url);

                    /// var response = await client.GetStringAsync(serviceName);
                    result = JsonConvert.DeserializeObject<TResp>(response);

                    //if (response.IsSuccessStatusCode)
                    //{

                    //    using (HttpContent _content = response.Content)
                    //    {
                    //        result = JsonConvert.DeserializeObject<TResp>(await _content.ReadAsStringAsync());
                    //    }

                    //}
                }
                catch (WebException ex)
                {
                    var webResponse = (HttpWebResponse)ex.Response;
                    if (webResponse != null)
                    {
                        HttpStatusCode = ((HttpWebResponse)webResponse).StatusCode;
                        HttpStatusCodeDescription = ((HttpWebResponse)webResponse).StatusDescription;
                        if (webResponse.Headers["X-StatusCode"] != null)
                        {
                            XStatusCode = int.Parse(webResponse.Headers["X-StatusCode"]);
                            if (webResponse.ContentLength > 0)
                            {
                                if (typeof(TResp) != typeof(object))
                                {
                                    using (var respStream = webResponse.GetResponseStream())
                                    {
                                        var reader = new StreamReader(respStream);
                                        string resulttmp = reader.ReadToEnd();
                                        result = JsonConvert.DeserializeObject<TResp>(resulttmp);
                                    }
                                }
                            }
                        }
                        webResponse.Close();
                    }
                }
            }

我在 android 应用程序中发现了两个问题。

  1. 网络配置文件丢失。

  2. 缺少 DNS 记录条目。

但是现在 Android App 方面的一切都运行良好。但是在 IOS 端遇到同样的问题,无法访问 HTTPS 请求。

标签: c#visual-studioxamarinxamarin.forms

解决方案


DNS 缓存超时

您使用的域名是否在您的网络上转换为与使用 4G 时不同的 IP 地址?

从wifi切换到4g时,我曾经遇到过类似的问题。在 android 应用程序中,dns 查找默认缓存 2 分钟(120000 毫秒),导致 webrequest 在连接到 4g 时仍使用本地 ip。

我通过System.Net.ServicePointManager.DnsRefreshTimeout = 0在android项目中设置解决了这个问题

自签名证书

另一种可能性是您使用的是自签名证书。Xamarin.Android 默认拒绝自签名证书。您可以通过将 分配ServicePointManager.ServerCertificateValidationCallback给一个函数来解决此问题,在该函数中检查证书签名是否符合自签名证书,或者始终返回 true(不推荐)。

现在根据这篇文章,不建议分配此静态 func 字段,而是使用自定义 HttpClientHandler 来覆盖该ServerCertificateCustomValidationCallback方法。

var handler = new HttpClientHandler
{
    // Change the func to check if the correct certificate is provided
    ServerCertificateCustomValidationCallback = (message, certificate, chain, errors) => true
};
var client = new HttpClient(handler);

您必须复制粘贴代码。出于某种原因,IntelliSense 不为成员提供建议ServerCertificateCustomValidationCallback


推荐阅读