c# - HTTPS 请求的 Xamarin 表单问题
问题描述
我使用Visual Studio 2017 Professional和Visual 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 应用程序中发现了两个问题。
网络配置文件丢失。
缺少 DNS 记录条目。
但是现在 Android App 方面的一切都运行良好。但是在 IOS 端遇到同样的问题,无法访问 HTTPS 请求。
解决方案
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
。
推荐阅读
- qemu - 如何设置 QEMU 会话的窗口标题?
- filter - 如何使用 infura 从以太坊区块中获取所有日志
- php - 获取PDF中的一行?
- scala - 如何引用/选择当前数据框中的列
- android - Android Studio 3.6.1 和 Gradle 构建问题
- r - 将关联函数与 na-Data 一起使用时出现 R 错误
- javascript - 为什么 iframe 无法在 Android Studio 上加载?
- powershell - 在 Terraform 中,如何以提升的权限执行 user_data Powershell 脚本?
- laravel - 如何在 cPanel 服务器上安装 nuxt?
- javascript - Express 路由器 ID 问题 - 将文本作为 ID 读取