C # HttpClient 现有连接被远程主机强制关闭

我的工作与替代支付整合使用他们的 托管页面集成。他们的 C # SDK 目前还没有这种集成,但是您可以看到它非常简单,我创建了一个小类来发送 post 请求并获得 JSON 响应。

我测试了我在 PostMan 和 cURL 上发送的 json 对象,它们都可以工作,还有身份验证头,所以我认为它们不是问题。下面是我的类的构造函数:

public AlternativePaymentsCli(string apiSecretKey)
{
this._apiSecretKey = apiSecretKey;


_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));


var authInfo = _apiSecretKey;
authInfo = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:", _apiSecretKey)));


// The two line below because I saw in an answer on stackoverflow.
_httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
_httpClient.DefaultRequestHeaders.Add("Keep-Alive", "3600");


_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Anything.com custom client v1.0");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);


}

我公布数据的方法是:

public string CreateHostedPageTransaction(HostedPageRequest req)
{
var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };


// I send this same json content on PostMan and it works. The json is not the problem
var content = new StringContent(JsonConvert.SerializeObject(req, settings), Encoding.UTF8, "application/json");
var response = _httpClient.PostAsync(this._baseUrl + "/transactions/hosted", content).Result;
var responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();


if (response.IsSuccessStatusCode)
return responseText;


return "";
}

然后我在 PostAsync 行得到这个错误: An existing connection was forcibly closed by the remote host,这是错误的详细信息:

[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) +8192811
System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) +47


[IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.]
System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) +294
System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) +149


[WebException: The underlying connection was closed: An unexpected error occurred on a send.]
System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) +324
System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) +137


[HttpRequestException: An error occurred while sending the request.]

我用的是 C # 4.5 Asp。网络 MVC。我一直在阅读同样错误的答案,到目前为止没有一个能解决我的问题。我漏掉了什么?

谢谢你的帮助

84104 次浏览

我在您的代码示例中没有看到设置 _ baseUrl 值的地方,但是我假设在某个地方已经这样做了。我还假设,因为这与支付有关,所以 URL 是 HTTPS。如果远程主机已经禁用了 TLS 1.0,并且您的连接是以 TLS 1.0的形式进入的,则可能会导致这种行为。我知道 C # 4.6默认支持 TLS 1.0/1.1.1.2,但我认为 C # 4.6仍然默认只支持 SSL3/TLS 1.0,即使支持 TLS 1.1和1.2。如果这是问题的原因,您可以使用以下代码手动向启用的值添加 TLS 1.1和1.2。

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

如果你正在使用。Net 4.0然后是 SecurityProtocolType。Tls11和 SecurityProtocolType。没有定义 Tls2,因此可以使用下面的硬编码值。

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

正如 这个绝妙的答案对类似问题所描述的那样,解决这个问题不需要对代码做任何修改:

将 Web 项目重新定位为 . 净值4.6 + ,然后更新 web.config,如下所示:

<system.web>
<compilation targetFramework="4.6" />
<httpRuntime targetFramework="4.6" />
</system.web>

这对我很有效,第一行确保协议 ssl3TLS1.2,第二行忽略任何潜在的证书错误(忽略和继续类似过期的证书):

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback +=  (sender, certificate, chain, sslPolicyErrors) => true;

对我来说,这个错误是由于忘记配置代理服务器造成的。 使用以下代码构造 HttpClient解决了我的.NET 4.7.2应用程序的问题:

var httpClientHandler = new HttpClientHandler { Proxy = WebRequest.GetSystemWebProxy() };
var httpClient = new HttpClient(httpClientHandler);

希望这对谁有帮助。