HttpClient.PostAsJsonAsync永远看不到帖子何时成功并做出响应
本文关键字:成功 响应 何时 PostAsJsonAsync 永远 看不到 HttpClient | 更新日期: 2023-09-27 17:53:21
我们使用HttpClient将json发布到restful web服务。在一个例子中,我们遇到了一些让我们困惑的事情。使用poster、fiddler等工具,我们可以发布到一个端点,并查看它是否正常工作。当我们对HttpClient.PostAsJsonAsync进行同样的操作时,我们可以在我们发布的软件中验证它接收到的数据是否正常。然而,我们的PostAsJsonAsync最终总是会超时,而不是给我们一个响应。
我们已经与创建我们正在使用的服务的团队合作,加上我们的额外测试,我们还没有能够真正暂停该服务。
每次我们使用HttpClient进行发布时,我们都可以验证我们发布的目标软件是否确实获得了数据。每当我们从任何其他工具发布到目标软件时,我们总是很快看到状态代码为200的响应。HttpClient无法接受来自此特定服务的响应。有人知道我们可以从这里看到什么吗?
这是代码(尽管它太像饼干了,我几乎不觉得需要它(
public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = client.PostAsJsonAsync(useUrl, o).Result;
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return response.Content.ReadAsStringAsync().Result;
}
return "";
}
}
这:
var response = client.PostAsJsonAsync(useUrl, o).Result;
导致代码死锁。在异步API上阻塞时通常会出现这种情况,这就是为什么您会遇到"我看不到任何响应">效果。
这是如何导致死锁的?事实上,您在包含同步上下文的环境中执行此请求,该同步上下文可能属于UI。它正在执行异步请求,当响应到达时,它通过IO完成线程继续,该线程试图将继续发布到当前被.Result
调用阻止的同一UI上下文上。
如果要同步发出HTTP请求,请改用WebClient
。如果您想正确利用异步API,那么使用await
而不是.Result
进行阻塞。
我遇到了同样的问题,这个SO回答为我解决了这个问题。
简而言之,您必须使用ConfigureAwait(false)
扩展来避免死锁:
var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
是否有原因不遵循异步等待模式?您正在调用一个异步方法,但没有等待它。您没有说明调用REST服务的代码是Windows窗体还是ASP.NET应用程序,但.Result
可能会导致您出现问题。
你能像这样重组你的方法吗:
public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
这是对@Justin Helgerson的解决方案的轻微修改。在您的方法中有2个阻止.Result
调用;一旦实现异步,就应该同时修复它们。
public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
注意,我还根据TAP模式将该方法重命名为PostDataAsync
。
System.Net.ServicePointManager.Expect100Continue = false;
在我们的案例中,这一行代码解决了问题。来自另一个团队的开发人员提出了这个建议,而且效果很好。我还没有在谷歌上搜索并阅读足够多的内容来解释它所解决的问题。