调用外部时出现 SocketException api
SocketException when calling external api
我正在使用自定义 class "ApiProvider"
从 Azure Function ServiceBusTrigger 调用我的 API
public class ApiProvider
{
private readonly string _backendUrl;
private static HttpClient _client;
private readonly TraceWriter _log;
public ApiProvider(TraceWriter log)
{
_pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
_log = log;
_client = CreateHttpClient();
}
}
我为 ServiceBus 队列中发送的每条消息调用它,假设有 1500 条消息,它将调用我支持的 1500 次。
有些调用是成功的,但有时我在 Azure Functions 日志中出错,没有太多信息!但根据 Application Insights:
System.Net.Sockets.SocketException
Exception while executing function: QueueDirectory An error occurred while sending the request. Unable to connect to the remote server Only one usage of each socket address (protocol/network address/port) is normally permitted
我认为将 HttpClient 设为静态就足够了,但它似乎并没有完全解决我猜想的问题,还是我遗漏了什么?
环境:
Azure Functions 运行时:1.0.11702.0
编辑:我的方法 CreateHttpClient():
private static HttpClient CreateHttpClient()
{
string thumbprint = Environment.GetEnvironmentVariable("WEBSITE_LOAD_CERTIFICATES");
if (thumbprint != null)
{
_log.LogInformation("Get the certificate of thumbprint : " + thumbprint);
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection =
certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
// Get the first cert with the thumbprint
var certificate = certCollection.OfType<X509Certificate2>().FirstOrDefault();
if (certificate != null)
{
_log.LogInformation("Certificate has been found.");
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(certCollection[0]);
return new HttpClient(handler);
}
_log.LogInformation("Certificate has not been found.");
}
}
return new HttpClient();
}
您应该只创建一次 HttpClient
,而不是为每个请求创建一次:
private static HttpClient _client = new HttpClient();
或者如果您需要保留初始化:
public class ApiProvider
{
private readonly string _backendUrl;
private static HttpClient _client;
private readonly TraceWriter _log;
static ApiProvider()
{
_client = CreateHttpClient();
}
public ApiProvider(TraceWriter log)
{
_pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
_log = log;
}
}
更新:
根据您的修改,我建议:
从 CreateHttpClient
中删除 _log
用法,如果您遇到证书加载问题,则抛出异常。这应该允许保持此方法静态,并且如果设置出现问题,也会快速且明显地失败。
如果您确实需要 CreateHttpClient
中的记录器,请将其设为非静态并使用您的原始代码,但只调用 CreateHttpClient
一次:
public ApiProvider(TraceWriter log)
{
_pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
_log = log;
if (_client == null) _client = CreateHttpClient();
}
可能存在一些竞争条件,但我认为这不是什么大问题。如果需要,请加锁。
我正在使用自定义 class "ApiProvider"
从 Azure Function ServiceBusTrigger 调用我的 APIpublic class ApiProvider
{
private readonly string _backendUrl;
private static HttpClient _client;
private readonly TraceWriter _log;
public ApiProvider(TraceWriter log)
{
_pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
_log = log;
_client = CreateHttpClient();
}
}
我为 ServiceBus 队列中发送的每条消息调用它,假设有 1500 条消息,它将调用我支持的 1500 次。
有些调用是成功的,但有时我在 Azure Functions 日志中出错,没有太多信息!但根据 Application Insights:
System.Net.Sockets.SocketException
Exception while executing function: QueueDirectory An error occurred while sending the request. Unable to connect to the remote server Only one usage of each socket address (protocol/network address/port) is normally permitted
我认为将 HttpClient 设为静态就足够了,但它似乎并没有完全解决我猜想的问题,还是我遗漏了什么?
环境: Azure Functions 运行时:1.0.11702.0
编辑:我的方法 CreateHttpClient():
private static HttpClient CreateHttpClient()
{
string thumbprint = Environment.GetEnvironmentVariable("WEBSITE_LOAD_CERTIFICATES");
if (thumbprint != null)
{
_log.LogInformation("Get the certificate of thumbprint : " + thumbprint);
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection =
certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
// Get the first cert with the thumbprint
var certificate = certCollection.OfType<X509Certificate2>().FirstOrDefault();
if (certificate != null)
{
_log.LogInformation("Certificate has been found.");
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(certCollection[0]);
return new HttpClient(handler);
}
_log.LogInformation("Certificate has not been found.");
}
}
return new HttpClient();
}
您应该只创建一次 HttpClient
,而不是为每个请求创建一次:
private static HttpClient _client = new HttpClient();
或者如果您需要保留初始化:
public class ApiProvider
{
private readonly string _backendUrl;
private static HttpClient _client;
private readonly TraceWriter _log;
static ApiProvider()
{
_client = CreateHttpClient();
}
public ApiProvider(TraceWriter log)
{
_pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
_log = log;
}
}
更新:
根据您的修改,我建议:
从
CreateHttpClient
中删除_log
用法,如果您遇到证书加载问题,则抛出异常。这应该允许保持此方法静态,并且如果设置出现问题,也会快速且明显地失败。如果您确实需要
CreateHttpClient
中的记录器,请将其设为非静态并使用您的原始代码,但只调用CreateHttpClient
一次:public ApiProvider(TraceWriter log) { _pamUrl = Environment.GetEnvironmentVariable("ApiUrl"); _log = log; if (_client == null) _client = CreateHttpClient(); }
可能存在一些竞争条件,但我认为这不是什么大问题。如果需要,请加锁。