【问题标题】:Encoding differences between using WebClient and WebRequest?使用 WebClient 和 WebRequest 之间的编码差异?
【发布时间】:2012-01-26 14:39:47
【问题描述】:

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

为什么会这样区分?

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

WebRequest request = WebRequest.Create(endpoint);
using (WebResponse response = request.GetResponse())
{
    Stream stream = response.GetResponseStream();
    StreamReader reader = new StreamReader(stream);
    string html = reader.ReadToEnd();
}

【问题讨论】:

  • 我猜,但这可能是因为WebClient.DownloadString 查看content-type 标头(例如“text/html; charset=utf-16”)来推断编码,但您的WebRequest 方法使用 UTF8(StreamReader 的默认值)
  • content-type 标头在这种情况下未指定字符集。
  • @Nico。然后它应该根据前导码(检测 BOM 和其他迹象)对 UTF-8、UTF-16LE、UTF-16BE 和 UTF-32 进行测试,最后默认使用默认的旧字符集,这恰好发生在与您机器上的站点相匹配。由于 HTTP 假定 Latin-1(毕竟是 90 年代初),因此最好明确地使用它作为“我不知道”的选择。

标签: c# webclient webrequest


【解决方案1】:

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

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

WebClient 几乎可以做到这一点:DownloadString 是一个更高级别的方法,WebRequest 及其派生类可以让您进入较低级别,它有一个调用“向 URI 发送 GET 请求,检查标头以查看正在使用的内容编码,如果您需要解压缩或解压缩它,请查看已使用的字符编码,使用该编码和流设置文本阅读器,然后调用ReadAll()"。普通的高级大块指令与低级小块指令的优缺点适用。

【讨论】:

  • 另外,如果您想反映 WebClient 的具体内容,请将 StreamReader 更改为 StreamReader reader = new StreamReader(stream, System.Text.Encoding.Default)
  • @ChrisHaas 不,它没有,那会更糟 - 尽管它可能在这种情况下工作 - 因为它适用于一种传统编码但不适用于 UTF-8。它检查标题并设置正确的标题 - 这可能与 System.Text.Encoding.Default 相同,但很可能不会。如果标头没有明确请求字符集,它会按顺序尝试 UTF-8、UTF-16LE、UTF-16BE 和 UTF-32,看看结果是否有意义。最后,如果失败,它会使用自己的 Encoding 属性。
  • @ChrisHaas 诚然,如果它没有找到一个 BOM 或一个零八位组可以放弃游戏,并且没有明确设置 Encoding,那将导致 System.Text.Encoding.Default 被用过。
  • 我只是说如何反映WebClient 所做的事情,而不是说它是好是坏。文档说WebClient 默认使用System.Text.Encoding.Default。就个人而言,我通常在使用不受我控制的网站时自己检查原始字节,如果我无法弄清楚,我会回退到标题。
  • @ChrisHaas 我知道你是对的,文档确实这么说。但是,如果您查看 ILSpy 或 Reflector,代码比文档说的要好。它首先检查 Content-Type 标头并尝试从中获取编码,然后对 BOM 进行一些测试,然后使用其Encoding 属性(默认为System.Text.Encoding.Default)作为最后的手段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2020-08-26
  • 1970-01-01
  • 1970-01-01
  • 2010-10-06
相关资源
最近更新 更多