从响应中读取文本

85
HttpWebRequest request = WebRequest.Create("http://google.com") as HttpWebRequest;  

request.Accept = "application/xrds+xml";  
HttpWebResponse response = (HttpWebResponse)request.GetResponse();  

WebHeaderCollection header = response.Headers;

谷歌返回文本。如何读取?

7个回答

144

你的 "application/xrds+xml" 给了我麻烦,我收到了 Content-Length 为 0 的响应(没有回复)。

在移除它之后,你可以使用 response.GetResponseStream() 访问响应。

HttpWebRequest request = WebRequest.Create("http://google.com") as HttpWebRequest;

//request.Accept = "application/xrds+xml";  
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

WebHeaderCollection header = response.Headers;

var encoding = ASCIIEncoding.ASCII;
using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
{
    string responseText = reader.ReadToEnd();
}

11
请注意,这里假定使用的是 ASCII 编码,但这可能是不正确的。 - Jon Skeet
1
请注意,检索响应文本不需要 WebHeaderCollection 行。 - Sam
1
请注意,HTTP响应没有被包含在using块中。如果在响应和下一个using块之间发生异常或返回,则连接不会关闭。 - Sam
@Sam,感谢你进行了多次编辑尝试,但我担心你的编辑结果被许多用户(在几个小时内有6个)大量点踩。我已经撤销了你的更改,并将尝试改进答案。 - STW
我已经得到了一个包含HttpResponseContext的结果,但是我无法将文本读入对象(可理解的格式)。例如:HttpResponseMessage response = wc.GetAsync(URI).Result; var contents = response.Content.ReadAsStringAsync();在这里,contents变量包含一些随机数据,而不是所需的数据。 - Krish
(我知道这是一个旧答案,但这可能会在未来帮助某些人)ReadAsStringAsync返回一个Task<string>,您需要在访问内容之前等待任务完成。 - mattumotu

86

被接受的答案没有正确处理WebResponse或解码文本。此外,在.NET 4.5中有一种新的方法来执行此操作。

要执行HTTP GET并读取响应文本,请执行以下操作。

.NET 1.1 ‒ 4.0

public static string GetResponseText(string address)
{
    var request = (HttpWebRequest)WebRequest.Create(address);

    using (var response = (HttpWebResponse)request.GetResponse())
    {
        var encoding = Encoding.GetEncoding(response.CharacterSet);

        using (var responseStream = response.GetResponseStream())
        using (var reader = new StreamReader(responseStream, encoding))
            return reader.ReadToEnd();
    }
}

.NET 4.5

private static readonly HttpClient httpClient = new HttpClient();

public static async Task<string> GetResponseText(string address)
{
    return await httpClient.GetStringAsync(address);
}

我假设你应该用参数名“address”替换“http://google.com”? - Ian Boyd
我非常喜欢这个答案。它非常简洁明了,处理编码也很正确;与被采纳的答案不同。它还展示了如何访问响应的“文本”,同样不同于被采纳的答案。 - Ian Boyd
这段代码对我来说会产生死锁,就像 https://dev59.com/S2kw5IYBdhLWcg3wbqES#10369275 中所描述的那样。 在它正常工作之前,需要加上 .GetStringAsync(address).ConfigureAwait(false);。 - Harmen

11

我刚刚自己尝试了一下,它给了我一个200 OK的响应,但没有内容 - 内容长度为0。你确定它给你返回了内容吗?无论如何,我会假设你真的得到了内容。

获取实际文本需要知道编码,这可能有点棘手。应该在Content-Type头部中找到它,但然后你还需要解析它等等。

但是,如果这实际上是XML(例如来自“http://google.com/xrds/xrds.xml”),那么就容易多了。只需将XML加载到内存中,例如通过LINQ to XML。例如:

using System;
using System.IO;
using System.Net;
using System.Xml.Linq;
using System.Web;

class Test
{
    static void Main()
    {
        string url = "http://google.com/xrds/xrds.xml";
        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);

        XDocument doc;
        using (WebResponse response = request.GetResponse())
        {
            using (Stream stream = response.GetResponseStream())
            {
                doc = XDocument.Load(stream);
            }
        }
        // Now do whatever you want with doc here
        Console.WriteLine(doc);
    }   
}

如果内容是XML,将结果转化为XML对象模型(无论是XDocumentXmlDocument还是XmlReader)可能比获取纯文本更有价值。


您需要检查流是否为空吗?(resharper建议) - Paul C
嗯,在反编译的方法中看起来并不清楚,为了安全起见,应该检查它是否为空。 - Paul C
1
@CodeBlend:然后做什么?如果这是一个预期的情况,我会抛出一个异常...无论如何,如果你将null传递给XDocument.Load,它也会发生异常,所以我认为没有好处。我通常不喜欢为了“以防万一,即使我认为它永远不会发生这种情况”而检查事物。这样做有时候是合适的,但如果你对每个方法都采取这种方式,最终会造成一团糟。 - Jon Skeet
我同意这会让代码变得冗长,但我现在面临一个困境,在必要时我绝对不想错过空值检查,但是并不总是清楚何时需要进行检查,而且我也不确定使用这个案例作为例子的逻辑如何使你认为它不能为null?我猜我在问应该在哪里划定界限,以使代码既健壮又不啰嗦? - Paul C
2
@CodeBlend:好的,如果你检查发现它确实是null,你会怎么做呢?在大多数情况下,你基本上无法继续执行,所以你需要抛出一个异常,说明某些东西意外地为空 - 而NullReferenceException或ArgumentNullException肯定会为你完成这个任务... - Jon Skeet

3
这篇文章提供了关于使用HttpWebResponse对象的良好概述:如何使用HttpWebResponse 以下是相关部分:
HttpWebResponse webresponse;

webresponse = (HttpWebResponse)webrequest.GetResponse();

Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream(),enc);

string Response = loResponseStream.ReadToEnd();

loResponseStream.Close();
webresponse.Close();

return Response;

如果一个Web服务器使用Windows代码页1252作为其编码,那么这是一个悲伤的日子:(你应该从响应中抓取它...这有点棘手。在这种特殊情况下,请参阅我的答案以获取解决方法。 - Jon Skeet
糟糕!这不是我的代码 :) 这是来自文章的代码,我只是想通过提供相关部分的快捷方式来帮助他。这就是随意提供帮助的危险 :) - CubanX

2
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.google.com");
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string strResponse = reader.ReadToEnd();

其他答案已经涵盖了这种做法。此外,我认为这种方法没有使用正确的编码来解码文本。 - Sam

1

response.GetResponseStream() 应该被用来返回响应流。并且不要忘记关闭 StreamResponse 对象。


0
如果您的HTTP请求是Post且request.Accept = "application/x-www-form-urlencoded";,那么我认为您可以通过以下代码获取响应文本:
var contentEncoding = response.Headers["content-encoding"];
                        if (contentEncoding != null && contentEncoding.Contains("gzip")) // cause httphandler only request gzip
                        {
                            // using gzip stream reader
                            using (var responseStreamReader = new StreamReader(new GZipStream(response.GetResponseStream(), CompressionMode.Decompress)))
                            {
                                strResponse = responseStreamReader.ReadToEnd();
                            }
                        }
                        else
                        {
                            // using ordinary stream reader
                            using (var responseStreamReader = new StreamReader(response.GetResponseStream()))
                            {
                                strResponse = responseStreamReader.ReadToEnd();
                            }
                        }

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