C# 使用WebClient和WebRequest之间的编码差异?

C# 使用WebClient和WebRequest之间的编码差异?,c#,webclient,webrequest,C#,Webclient,Webrequest,在获取一些随机的西班牙报纸索引时,我没有正确地使用WebRequest获取变音符号,它们产生了一个奇怪的字符:�,使用WebClient从同一uri下载响应时,我得到了相应的响应 为什么会出现这种差异 var client = new WebClient(); string html = client.DownloadString(endpoint); vs 在创建流读取器时,您只是假设实体在UTF-8中,而没有显式设置编码。您应该检查HttpWebResponse的CharacterSet(

在获取一些随机的西班牙报纸索引时,我没有正确地使用WebRequest获取变音符号,它们产生了一个奇怪的字符:
,使用
WebClient
从同一uri下载响应时,我得到了相应的响应

为什么会出现这种差异

var client = new WebClient();
string html = client.DownloadString(endpoint);
vs


在创建流读取器时,您只是假设实体在UTF-8中,而没有显式设置编码。您应该检查
HttpWebResponse
CharacterSet
(未被
WebResponse
基类公开),并使用适当的编码打开
StreamReader

否则,如果它像读取UTF-8一样读取非UTF-8的内容,它将遇到在UTF-8中无效的八位字节序列,并且必须替换为U+FFFD替换字符(
)尽其所能


WebClient的功能非常强大:
DownloadString
是一种更高级别的方法,当
WebRequest
及其派生类允许您进入较低级别时,它只需调用“向URI发送GET请求,检查标题以查看使用了什么内容编码,如果需要取消gzip或对其进行反压缩,请查看使用了什么字符编码,使用该编码和流设置文本读取器,然后调用
ReadAll()
“。普通高级大数据块指令与低级小数据块指令的优缺点适用。

我猜,但这可能是因为
WebClient.DownloadString
查看
内容类型
标题(例如“text/html;charset=utf-16”)来推断编码,但WebRequest方法使用UTF8(StreamReader的默认值)在这种情况下,
内容类型
标题没有指定字符集。@Nico。然后,它应该根据前ambles对UTF-8、UTF-16LE、UTF-16BE和UTF-32进行测试(以检测BOM和其他信号装置)最后默认为默认的遗留字符集,该字符集恰好与您计算机上站点的字符集相匹配。由于HTTP采用拉丁语-1(毕竟,这是90年代早期),因此可以明确地将其用作“我不知道”选择。另外,如果您想镜像
WebClient
具体执行的操作,请将
StreamReader
更改为
StreamReader=newstreamreader(stream,System.Text.Encoding.Default)
@ChrisHaas不,它没有,那会更糟-尽管在这种情况下它可能会工作-因为它可以用于一种传统编码,但不适用于UTF-8。它检查头并设置正确的头-可能与System.Text.encoding.Default相同,但很可能不会。如果没有显式请求字符集,则根据标题,它依次尝试UTF-8、UTF-16LE、UTF-16BE和UTF-32,看看结果是否有意义。最后,如果失败,它将使用自己的
编码属性。@ChrisHaas同意,如果它没有找到泄露游戏的BOM或零八位字节,并且没有显式设置
编码,那将导致
System.Text.Encoding.Default
正在使用。我只是说如何镜像
WebClient
的功能,而不是它的好坏。文档说
WebClient
默认使用
System.Text.Encoding.Default
。就我个人而言,在处理我无法控制的站点时,通常会检查原始字节本身如果我无法理解,请返回标题。@ChrisHaas我知道你是对的,文档确实这么说。如果你查看ILSpy或Reflector,代码比文档说的要好。它首先检查内容类型标题并尝试从中获取编码,然后对BOM进行一些测试,然后使用其
编码
属性(默认为
System.Text.Encoding.Default
)作为最后手段。
WebRequest request = WebRequest.Create(endpoint);
using (WebResponse response = request.GetResponse())
{
    Stream stream = response.GetResponseStream();
    StreamReader reader = new StreamReader(stream);
    string html = reader.ReadToEnd();
}