0

我正在尝试从 WEB API 加载 JSON 数据。如果我从任何浏览器请求数据,URL 工作正常。如果我尝试使用 webClient 获取数据,则相同的 URL 不起作用。它抛出以下错误:

A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) +111    
[IOException: Unable to read data from the transport connection: A connection attempt failed     because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.]

System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) +299
    [WebException: The underlying connection was closed: An unexpected error occurred on a receive.]
       System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request) +298
       System.Net.WebClient.DownloadString(Uri address) +106

我发现这样可能会堆栈溢出类似的问题并实施 TSL 安全协议和标头更改,但仍然无法正常工作。

下面是我的代码:

 PCR IWebClientServices<PCR>.PrepareWebClient(string PreparedURL)
    {
        try
        {
            //this code bypass the SSL exception
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | 
                                                   SecurityProtocolType.Tls11 | 
                                                   SecurityProtocolType.Tls;
            //now we will invoke the webClient
            var webClient = new WebClient();
            webClient.Headers.Add(HttpRequestHeader.Cookie, "cookievalue");
            webClient.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0");
            var json = webClient.DownloadString(PreparedURL);
            return JsonConvert.DeserializeObject<PCR>(json);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            return null;
        }
    }

我被困在这里,因为这段代码有时工作得很好,有时根本不起作用。我不知道出了什么问题,但我认为在请求浏览器请求等数据时我遗漏了一些东西,但服务器正在捕获一些可疑的请求并且没有响应。但是,如果我从浏览器浏览 URL,它会发送数据。

4

2 回答 2

0

为了支持 TLS 1.2 连接,应以 .NET 4.7.2 为目标。

当您想确保应用程序在某个运行时运行时,请确保配置文件中存在以下部分:

应用程序配置

<configuration>

 <startup>
   <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
 </startup>
</configuration>

网页配置

 <system.web>
   <compilation debug="true" targetFramework="4.7.2" /> 
   <httpRuntime targetFramework="4.7.2" maxRequestLength="102400" />
 </system.web>
</configuration>

补充说明:

我不确定这是否会成为问题,但 webclient 是一种不推荐使用的调用 web 服务的方式,您应该更喜欢 httpclient 来发出请求。

于 2020-01-13T12:11:53.830 回答
0

最后我能够解决这个问题。问题是因为服务器已使用 AES128 证书将其 SSL 升级到 TLS 1.2。我将 webclient 更改为 httpclient 并避免使用块。

using(var client = new HttpClient())
{
    //I removed this code as using block code serves only one time
    // And was failing for next subsequent request
}

我进行了很多搜索,发现如果您在 using 块中使用 HttpClient,则该对象将被释放,但 TCP 连接将保持打开状态。它不会被关闭。因此,上述方法适用于单个请求,并且由于此问题,下一个后续请求失败。

所以我遵循以下方法,最后我的代码现在像魅力一样工作。

我在我的类中将 HttpClient 对象初始化为静态

private static HttpClient httpClient = new HttpClient();

然后我为我的泛型类调用它,将所有信息传递给它并返回我想要的结果。

以下是完整的工作代码:

public class MyWebClientServices
{
    private static HttpClient httpClient = new HttpClient();

    public T PrepareWebClient<T>(string preparedURL)
    {
        try
        {
          // As my server is using TLS1.2 I kept only that protocol
          ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

          httpClient.DefaultRequestHeaders.Accept.Clear();
          httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualtiyHeaderValue("application/json");
          var json = httpClient.GetStringAsync(preparedURL).Result;
          //here T is generic PCR class. I have created generic classes for which I need to invoke httpClient & their respective urls as I want to use this same code for all.
          //If your class is not generic then instead of T you can use your class
          T tJson = JsonConvert.DeserializeObject<T>(json);
          return (T)Convert.ChangeType(tJson, typeof(T));
         //finally my issue has been fixed and I'm getting data on all subsequent requests too
    }
    catch(Exception e)
    {
        throw e;
    }

}//end of MyWebClientServices class

我参考了下面的博客,其中包含与此问题相关的所有信息: https ://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

2)如果您正在为 httpClient 创建单例模式并共享,那么它也有严重的行为。

那就是 HttpClientHandler 创建一个连接组(以其哈希码命名)并且在被处理之前不会关闭组中的连接。这基本上意味着只要连接打开,DNS 检查就不会发生。

一个天真的解决方案是在每次使用 HttpClient(因此是 HttpClientHandler)时处理它。

另一种解决方案是在 HttpClient 上设置 DefaultRequestHeaders 的 ConnectionClose 属性:

var client = new HttpClient();
client.DefaultRequestHeaders.ConnectionClose = true;

这会将 HTTP 的 keep-alive 标头设置为 false,因此套接字将在单个请求后关闭。事实证明,这可能会为您的每个 HTTP 调用增加大约 35 毫秒(带有长尾,即放大异常值),从而阻止您利用重用套接字的好处。那么解决方案是什么呢?

现在要修复它,我们需要做的就是通过将 URL 传递给端点并设置 ConnectionLeaseTimeout 来获取端点的 ServicePoint 对象:

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 minute

第二部分我没有使用过,但如果有人想使用单例模式,请在此处发布。更详细的信息可以在下面的博客中获得,重要的部分我在这里发布,以防万一链接被破坏: http ://byterot.blogspot.com/2016/07/singleton-httpclient-dns.html

我希望这会帮助像我这样被困住的人。

于 2020-04-20T19:45:42.290 回答