从 HttpResponseMessage 获取内容/消息

Posted

技术标签:

【中文标题】从 HttpResponseMessage 获取内容/消息【英文标题】:Getting content/message from HttpResponseMessage 【发布时间】:2013-04-02 21:42:06 【问题描述】:

我正在尝试获取 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

【问题讨论】:

【参考方案1】:

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

txtBlock.Text = await response.Content.ReadAsStringAsync(); //right!

这样你就不需要引入任何流阅读器,也不需要任何扩展方法。

【讨论】:

不知道为什么这不是公认的答案,尤其是因为这使您能够轻松地将内容序列化到您的对象中。 ReadAsStringAsync 不能很好地处理错误恕我直言。 你也可以使用 Response.Content.ReadAsStringAsync().Result 而不是 await 但请注意:如果响应中有表情符号或其他一些 Unicode 字符,ReadAsStringAsync() 可能会抛出异常。我不得不使用 Streams(就像在接受的答案中一样)来克服这个问题。【参考方案2】:

您需要致电GetResponse()。

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

【讨论】:

谢谢,但为什么我在这里得到这个错误:“System.Net.Http.HttpResponseMessage'不包含'GetResponseStream'的定义,并且没有扩展方法'GetResponseStream'接受'类型的第一个参数System.Net.Http.HttpResponseMessage' 可以找到" @Klemzy - 因为您将其称为异步。尝试改用 Content 属性。看看example here。向下滚动到第二步。 @Klemzy - 看看example here。向下滚动到第二步。如果你不明白,我会编辑我的答案并给你一个例子 这个答案完全是题外话,OP使用的是HttpClient,而不是HttpWebRequest / HttpWebResponse 问题是关于 HttpCient,您的回答是基于过时和过时的 HttpWebRequest。【参考方案3】:

试试这个,你可以像这样创建一个扩展方法:

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

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

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

希望对你有帮助;-)

【讨论】:

到目前为止最容易启动和运行 如果您的代码无法处理异步编程,请使用 await 而不是 .Result... 或使用同步 HTTP 客户端。但是任何现代代码都应该这样做,否则它可能表明您的应用程序做错了。【参考方案4】:

如果您想将其转换为特定类型(例如在测试中),您可以使用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>();

【讨论】:

object yourTypeInstance = await response.Content.ReadAsAsync(typeof(YourType));应该是 var yourTypeInstance = await response.Content.ReadAsAsync(); 我使用 Request.Content.ReadAsAsync 来解析 Json 并获得了糟糕的性能。【参考方案5】:

根据 rudivonstaden 的回答

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

但如果你不想让方法异步,你可以使用

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

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

【讨论】:

使用.Result有什么不同吗?httpContent.ReadAsStringAsync().Result .Result 会阻止线程在该行上的执行......而 txtBlock.Text.Wait() 阻止 wait() 调用......所以你是对的,基本上没有区别。但我怀疑txtBlock.Text.Wait() 会采用一个可选的整数参数,因此如果之前的ReadAsStringAsync() 调用永远不会返回,GUI 不会挂起。例如,以下内容将阻止不超过 1 秒 txtBlock.Text.Wait(1000)【参考方案6】:

我建议的快速答案是:

response.Result.Content.ReadAsStringAsync().Result

【讨论】:

不要在任务上致电Result。您可能会锁定您的应用程序。请改用 async/await。 我不会说永远不会...有时又快又脏可以完成它。但我同意您确实冒着ReadAsStringAsync() 不返回的风险,因此请确保不要在您的 GUI 或主应用程序线程上调用它。 好或几乎好。我需要这样编码: HttpResponseMessage response = ....; var responseBody = 等待响应?.Content.ReadAsStringAsync(); 如果我正确理解您的问题,我会回答“差不多好”。根据您的代码执行模式(例如单线程或多线程)应该确定您的方法。关于您正在评论的这个答案(假设单线程执行没问题),那么我会打电话给var responseBody = response.Content.ReadAsStringAsync().Result; 在任务上调用.Result 通常是不好的做法,你会阻塞主线程。【参考方案7】:

我认为下图有助于那些需要以T 作为返回类型的人。

【讨论】:

【参考方案8】:

你可以使用GetStringAsync方法:

var uri = new Uri("http://yoururlhere");
var response = await client.GetStringAsync(uri);

【讨论】:

【参考方案9】:

使用块:

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

此函数将创建新的 HttpClient 对象,将 http-method 设置为 GET,将请求 URL 设置为函数“Url”字符串参数,并将这些参数应用于 HttpRequestMessage 对象(定义 SendAsync 方法的设置)。最后一行:函数向指定的 url 发送异步 GET http 请求,等待响应消息的 .Result 属性(只是完整的响应对象:headers + body/content),获取该完整响应的 .Content 属性(请求的正文,没有 http headers),将 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-request 的完整“转换”路径,并使用 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://***.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 *** main page html*/
Console.ReadLine(); /*press enter to finish*/

完整代码:

【讨论】:

以上是关于从 HttpResponseMessage 获取内容/消息的主要内容,如果未能解决你的问题,请参考以下文章

如何从 HttpResponseMessage 中获取特定的标头值

如何从HttpResponseMessage获取特定的标头值

异步任务<HttpResponseMessage> 获取 VS HttpResponseMessage 获取

C# 无法通过 HttpResponseMessage 获取 HTTP 返回代码

如何确定是不是使用 HttpClient 从缓存中完成了 HttpResponseMessage

C# 从 HttpResponseMessage 读取