调用外部api时出现SocketException

时间:2018-05-07 20:51:14

标签: azure-functions servicebus

我使用自定义类" 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 Log中有错误而没有太多信息!但根据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 Runtime: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();
    }

1 个答案:

答案 0 :(得分:1)

您应该只创建一次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;
    }
}

更新:

根据你的编辑,我建议:

  1. _log中删除CreateHttpClient用法,如果您遇到证书加载问题,则只会抛出异常。这应该允许保持此方法静态,并且如果设置存在问题,也会快速且明显地失败。

  2. 如果您确实需要CreateHttpClient中的记录器,请将其设置为非静态并使用原始代码,但只需拨打CreateHttpClient一次:

    public ApiProvider(TraceWriter log)
    {
        _pamUrl = Environment.GetEnvironmentVariable("ApiUrl");
        _log = log;
        if (_client == null) _client = CreateHttpClient();
    }
    

    某种竞争条件是可能的,但我不会发现这个问题。如果需要,可以添加锁定。