【问题标题】:HttpClient cannot send second request after retry重试后HttpClient无法发送第二个请求
【发布时间】:2015-12-16 20:52:41
【问题描述】:

最初我想发送没有客户端证书的第一个请求,如果错误是“身份验证错误”,那么我想重新发送附有证书的请求。所以代码首先是

HttpStringContent ehttpContent = new HttpStringContent(content);
HttpRequestMessage req2 = new HttpRequestMessage(method, resourceUri);
req2.Headers.Add("SOAPAction", soapAction);
req2.Content = ehttpContent;
req2.Content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");

bool retry= await FirstLoginAttempt(...);

if( retry) {

 newHttpClient = new HttpClient(baseFilter2);

 try
 {
     cts.CancelAfter(Constants.HttpTimeOut);
     System.Diagnostics.Debug.WriteLine(ehttpContent);
     eresponse = await newHttpClient.SendRequestAsync(req2).AsTask(cts.Token);

     if (cts != null)
     {
        cts.Dispose();
        cts = null;
 } catch { ... }


}

前面的代码调用 FirstLoginAttempt 可能会因证书错误而失败。它返回 true 或 false,然后前面的代码尝试发送带有证书的新 httpClient。

public static async Task<bool> FirstLoginAttempt() {

httpClient = new HttpClient();

try
{
    cts.CancelAfter(Constants.HttpTimeOut);
    var operation = httpClient.SendRequestAsync(ereq).AsTask(cts.Token);
    eresponse = await operation;
    if (cts != null) { cts.Dispose(); cts = null; }

}
catch (TaskCanceledException e)
{
  if (cts != null) { cts.Dispose(); cts = null; }
   throw e;
}
catch (Exception exx)
{ ... }
}

当第一次登录尝试返回 true 以便再次尝试时,第二个 httpclient(具有相同的内容)失败并且异常说我不能两次发送相同的请求。那可能意味着之前的操作没有完成?我该如何解决我的问题?我能否以某种方式确定第一个请求生命周期已结束以便重试?

我的环境是Windows Phone 8.1

更新 #1。 使用 lambda 后

StackTrace = " 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r\n 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n ... Message = "HRESULT 异常:0x80072EFD"(不成功时抛出)

在堆栈跟踪之上 ... ...

 Func<HttpRequestMessage> httpRequestCreator = () =>
                {
     HttpStringContent ehttpContent = new HttpStringContent(content);

     var req = new HttpRequestMessage(method, resourceUri)
     {
         Content = ehttpContent
     };
     req.Headers.Add("SOAPAction", soapAction);
     req.Content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");
     return req;
};

if (cts != null) { cts.Dispose(); cts = null; }

cts = new System.Threading.CancellationTokenSource();
newHttpClient = new HttpClient();

try
{
    cts.CancelAfter(Constants.HttpTimeOut);
    eresponse = await newHttpClient.SendRequestAsync(httpRequestCreator()).AsTask(cts.Token);

    if (cts != null) { cts.Dispose(); cts = null; }

}
catch (TaskCanceledException e
{
    if (cts != null) { cts.Dispose(); cts = null; }
    throw e;
}
catch (Exception exx)
{
    exception2 = exx;
    ...
    ...
}

【问题讨论】:

    标签: c# .net windows-phone-8.1 dotnet-httpclient asynchttpclient


    【解决方案1】:

    问题在于您正在为这两个请求重新使用您的HttpRequestMessage,这是您无法做到的。相反,为您要发送的每条消息创建一个新请求。解决这个问题的一种方法是创建一个Func&lt;HttpRequestMessage&gt;,它每次都会返回一个新实例:

    Func<HttpRequestMessage> httpRequestCreator = () => 
    {
         var request = new HttpRequestMessage(method, resourceUri)
         {
              Content = content
         };
         request.Headers.Add("SOAPAction", soapAction);
         request.Content.Headers.ContentType =
                                HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8"); 
         return request;
    };
    
    bool retry = await FirstLoginAttempt(httpRequestCreator());
    // If re-try is needed:
    var operation = await httpClient.SendRequestAsync(httpRequestCreator()).AsTask(cts.Token);
    

    附带说明 - 不要对正常代码执行路径进行异常处理。相反,请考虑发送身份验证信息,即使它可能不需要,或者请求您查询的服务在运行时提供有关您是否需要传递该信息的信息。

    【讨论】:

    • 如何在新的 httpRequestCreator 中添加内容、标题等?例如,在我的代码中,我使用 req2.Content = ehttpContent;现在怎么通过?
    • @cateof 编辑了我的代码以使其清晰。您可以隐式捕获它或将其作为参数传递给Func
    • 这些行怎么样? req.Headers.Add("SOAPAction", soapAction); req.Content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");
    • @cateof 再次编辑。您应该真正研究 lambda 表达式语法的工作原理。这并不复杂。
    • 当然我对 C# 还是很陌生。根据您的建议,我已经更新了我的答案。我收到一个异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多