从HttpResponseMessage获取内容/消息

256

我正在尝试获取HttpResponseMessage的内容。它应该是:{"message":"Action '' does not exist!","success":false},但我不知道如何从HttpResponseMessage中获取它。

HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.GetAsync("http://****?action=");
txtBlock.Text = Convert.ToString(response); //wrong!
在这种情况下,txtBlock 的值将为:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Vary: Accept-Encoding
  Keep-Alive: timeout=15, max=100
  Connection: Keep-Alive
  Date: Wed, 10 Apr 2013 20:46:37 GMT
  Server: Apache/2.2.16
  Server: (Debian)
  X-Powered-By: PHP/5.3.3-7+squeeze14
  Content-Length: 55
  Content-Type: text/html
}
10个回答

534

我认为最简单的方法就是只更改最后一行

txtBlock.Text = await response.Content.ReadAsStringAsync(); //right!
这样你就不需要引入任何流阅读器,也不需要任何扩展方法。

8
不确定为什么这不是被接受的答案,特别是因为它让你能够轻松地将内容序列化到你的对象中。 - Jason McKindly
5
我认为,ReadAsStringAsync 在错误处理方面表现不佳。 - stannius
30
你可以使用Response.Content.ReadAsStringAsync().Result来代替使用await。 - Justin
8
请注意:如果响应中包含表情符号或其他Unicode字符,则ReadAsStringAsync()可能会抛出异常。我不得不使用流(就像接受的答案中那样)来克服这个问题。 - Ginkgo
这太不符合直觉了!为什么他们没有让它更明显呢?同意这应该是被接受的答案。很高兴它得到了最多的投票。 - Avrohom Yisroel
1
@Justin,在使用异步方法时,请不要使用Result属性,而是将其完全等待。Result属性可能会导致死锁。详细信息请参考:https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#async-all-the-way - undefined

77

你需要调用 GetResponse() 方法。

Stream receiveStream = response.GetResponseStream ();
StreamReader readStream = new StreamReader (receiveStream, Encoding.UTF8);
txtBlock.Text = readStream.ReadToEnd();

39
谢谢,但是为什么我在这里会收到这个错误消息: "System.Net.Http.HttpResponseMessage' 不包含名为 'GetResponseStream' 的定义,并且没有接受类型为 'System.Net.Http.HttpResponseMessage' 的第一个参数的扩展方法 'GetResponseStream' 可用。" - Clem
19
@Klemzy - 因为你正在异步调用它。尝试使用Content属性代替。查看此处的示例,并向下滚动到第二步。 - Icemanind
2
@Klemzy - 看看这里的示例。向下滚动到第二步。如果你无法理解,我会编辑我的答案并为你提供一个示例。 - Icemanind
25
这个回答完全跑题了,原问题使用的是HttpClient,而不是HttpWebRequest/HttpWebResponse - Maxime Rossini
3
这个问题涉及到HttpClient,而你的回答基于过时且已废弃的HttpWebRequest。 - Payam
显示剩余2条评论

45

你可以尝试创建一个类似这样的扩展方法:

    public static string ContentToString(this HttpContent httpContent)
    {
        var readAsStringAsync = httpContent.ReadAsStringAsync();
        return readAsStringAsync.Result;
    }

然后,简单地调用扩展方法:

txtBlock.Text = response.Content.ContentToString();

希望这能帮到你 ;-)


到目前为止,最容易上手和运行的。 - Aage
2
请使用await代替.Result,或者如果您的代码无法处理异步编程,请使用同步HTTP客户端。但是任何现代化的代码都应该能够处理异步编程,否则这可能意味着您的应用程序存在问题。 - Maxime Rossini

17
如果您想将其转换为特定类型(例如,在测试中),可以使用ReadAsAsync扩展方法:ReadAsAsync
object yourTypeInstance = await response.Content.ReadAsAsync(typeof(YourType));

或者以下是用于同步代码的:

object yourTypeInstance = response.Content.ReadAsAsync(typeof(YourType)).Result;

更新:还有一个通用选项ReadAsAsync<>,它返回特定类型实例而不是对象声明的实例:

YourType yourTypeInstance = await response.Content.ReadAsAsync<YourType>();

3
应该改为:var yourTypeInstance = await response.Content.ReadAsAsync<YourType>(); 这段代码的作用是将 HTTP 响应内容转换成指定类型(YourType)的对象。使用泛型方法能够更加简洁和清晰地表达这一意图。 - Thomas.Benz
我使用了Request.Content.ReadAsAsync来解析Json,但性能非常差。 - W.Leto

8
通过rudivonstaden的回答
txtBlock.Text = await response.Content.ReadAsStringAsync();

但是,如果你不想把这个方法变成异步方法,你可以使用

txtBlock.Text = response.Content.ReadAsStringAsync();
txtBlock.Text.Wait();

Wait()很重要,因为我们正在进行异步操作,在继续之前必须等待任务完成。


3
使用.Result有何不同?httpContent.ReadAsStringAsync().Result的意思是将HttpContent转换成字符串并获取结果。 - mkb
.Result would block the thread's execution on that line... where as txtBlock.Text.Wait() blocks on the wait() call... so you're correct that basically there is no difference. But I suspect txtBlock.Text.Wait() would take a optional integer parameter so the GUI does not hang if the previous ReadAsStringAsync() call never returns. For example the following would block for no more than 1 second txtBlock.Text.Wait(1000) - benhorgen

7
我建议的快速答案是:

response.Result.Content.ReadAsStringAsync().Result

意思是:使用该代码可以读取响应结果的内容。

4
不要在任务上调用“Result”。这样做可能会导致您的应用程序锁死。请改用async/await。 - eltiare
很好或者几乎很好。我需要像这样编码:HttpResponseMessage response = ....; var responseBody = await response?.Content.ReadAsStringAsync(); - Gerard Jaryczewski
1
通常不建议在任务上调用.Result,这会阻塞主线程。 - db2
响应中没有Result属性。正确的做法是 string result = await response.Content.ReadAsStringAsync() - John Sivertsen
1
调用await是否也会隐式阻塞主线程?即与获取.Result相同。 - OneCricketeer
显示剩余2条评论

1

我认为以下图片对于那些需要了解返回类型 T 的人会有所帮助。

enter image description here


0
您可以使用GetStringAsync方法:
var uri = new Uri("http://yoururlhere");
var response = await client.GetStringAsync(uri);

0

使用块:

using System;
using System.Net;
using System.Net.Http;

这个函数将创建一个新的HttpClient对象,将http方法设置为GET,将请求URL设置为函数“Url”字符串参数,并将这些参数应用于HttpRequestMessage对象(定义SendAsync方法的设置)。最后一行:函数发送异步GET http请求到指定的url,等待响应消息的.Result属性(完整的响应对象:头+正文),获取该完整响应的.Content属性(请求的正文,不包括http头),对该内容(也是某种特殊类型的对象)应用ReadAsStringAsync()方法,最后再次使用.Result属性等待此异步任务完成,以获取最终结果字符串,然后将此字符串作为我们函数的返回值。

static string GetHttpContentAsString(string Url)
    {   
        HttpClient HttpClient = new HttpClient();
        HttpRequestMessage RequestMessage = new HttpRequestMessage(HttpMethod.Get, Url);
        return HttpClient.SendAsync(RequestMessage).Result.Content.ReadAsStringAsync().Result;
    }

这是一个更简短的版本,不显示我们的http请求的完整“转换”路径,并使用HttpClient对象的GetStringAsync方法。该函数只是创建了一个HttpClient类的新实例(即HttpClient对象),使用GetStringAsync方法获取我们的http请求的响应正文(内容)作为异步任务结果/承诺,然后使用该异步任务结果的.Result属性获取最终字符串,最后将此字符串作为函数返回值简单地返回。

static string GetStringSync(string Url)
    {
        HttpClient HttpClient = new HttpClient();
        return HttpClient.GetStringAsync(Url).Result;
    }

使用方法:

const string url1 = "https://microsoft.com";
const string url2 = "https://stackoverflow.com";

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; /*sets TLC protocol version explicitly to modern version, otherwise C# could not make http requests to some httpS sites, such as https://microsoft.com*/

Console.WriteLine(GetHttpContentAsString(url1)); /*gets microsoft main page html*/
Console.ReadLine(); /*makes some pause before second request. press enter to make second request*/
Console.WriteLine(GetStringSync(url2)); /*gets stackoverflow main page html*/
Console.ReadLine(); /*press enter to finish*/

完整代码:

enter image description here


如果你使用return await x.ReadAsStringAsync();而不是明确请求结果,我觉得代码会更简洁。在这种情况下,它实现的是同样的功能。然而,在某些情况下,这可能会对性能造成影响。此外,await是最佳实践推荐的做法。 - undefined

0

截至2022年2月更新的答案:

var stream = httpResponseMessage.Content.ReadAsStream();
var ms = new MemoryStream();
stream.CopyTo(ms);
var responseBodyBytes = ms.ToArray();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接