Ruby Mechanize中text / csv Content-Encoding = UTF-8的问题

时间:2013-09-15 00:04:23

标签: ruby mechanize mechanize-ruby

尝试使用Mechanize V2.5.1加载具有UTF-8编码的CSV页面时,我使用了以下代码:

a.content_encoding_hooks << lambda{|httpagent, uri, response, body_io|
 response['Content-Encoding'] = 'none' if response['Content-Encoding'].to_s == 'UTF-8'
}
p4 = a.get(redirect_url, nil, ['accept-encoding' => 'UTF-8'])

但是我发现内容编码挂钩没有被调用,我得到以下错误和回溯:

/Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:787:in 'response_content_encoding': unsupported content-encoding: UTF-8 (Mechanize::Error)
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:274:in 'fetch'
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:949:in 'response_redirect'
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:299:in 'fetch'
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:949:in 'response_redirect'
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/http/agent.rb:299:in 'fetch'
    from /Users/jackrg/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize.rb:407:in 'get'
    from prototype/test1.rb:307:in `<main>'

有没有人知道为什么内容钩子代码没有被触发以及为什么我会收到错误?

1 个答案:

答案 0 :(得分:1)

  

但是我发现内容编码挂钩没有被调用

是什么让你这么想?

错误消息引用此代码:

  def response_content_encoding response, body_io
    ...
    ...

    out_io = case response['Content-Encoding']
             when nil, 'none', '7bit', "" then
               body_io
             when 'deflate' then
               content_encoding_inflate body_io
             when 'gzip', 'x-gzip' then
               content_encoding_gunzip body_io
             else
               raise Mechanize::Error,
                 "unsupported content-encoding: #{response['Content-Encoding']}"

因此,机械化只识别内容编码:'7bit','deflate','gzip'或'x-gzip'。

来自HTTP / 1.1规范:

  

4.11内容编码

     

Content-Encoding实体标题字段用作修饰符   媒体类型。如果存在,其值表示附加内容   编码已经应用于实体 - 身体,因此解码   必须应用机制才能获得媒体类型   由Content-Type标头字段引用。内容编码是   主要用于允许压缩文档而不会丢失   其基础媒体类型的身份。

   Content-Encoding  = "Content-Encoding" ":" 1#content-coding
     

内容编码在第3.5节中定义。其使用的一个例子是

   Content-Encoding: gzip
     

内容编码是由...识别的实体的特征   Request-URI中。通常,实体主体与此编码一起存储   并且仅在渲染或类似用法之前解码。但是,一个   非透明代理可以修改内容编码,如果是新编码   已知接收者可以接受,除非“无变换”   缓存控制指令出现在消息中。

     

...   ...

     

3.5内容编码

     

内容编码值表示具有的编码转换   已经或可以应用于实体。 内容编码主要是   用于允许压缩文档或其他有用的文档   转换而不失去其底层媒体类型的身份   而且不会丢失信息。通常,实体存储在   编码形式,直接传输,仅由接收方解码。

   content-coding   = token
     

所有内容编码值都不区分大小写。 HTTP / 1.1使用   Accept-Encoding中的内容编码值(第14.3节)和   Content-Encoding(第14.11节)标题字段。虽然价值   描述内容编码,更重要的是它   指示删除的解码机制   编码

     

互联网号码分配机构(IANA)作为注册机构   内容编码值令牌。 最初,注册表包含   跟随代币

     

gzip 由RFC 1952 [25]中描述的文件压缩程序“gzip”(GNU zip)生成的编码格式。这种格式是   Lempel-Ziv编码(LZ77),带32位CRC。

     

compress 通用UNIX文件压缩程序“compress”生成的编码格式。这种格式是自适应的   Lempel-Ziv-Welch编码(LZW)。

    Use of program names for the identification of encoding formats
    is not desirable and is discouraged for future encodings. Their
    use here is representative of historical practice, not good
    design. For compatibility with previous implementations of HTTP,
    applications SHOULD consider "x-gzip" and "x-compress" to be
    equivalent to "gzip" and "compress" respectively.
     

deflate RFC 1950 [31]中定义的“zlib”格式与RFC 1951 [29]中描述的“deflate”压缩机制相结合。

     

身份默认(身份)编码;没有任何转变的使用。此内容编码仅用于   Accept- Encoding标头,不应该在   内容编码标题。
  http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5

换句话说,http 内容编码与ascii v.utf-8 v.latin-1无关。

此外,Mechanize :: HTTP :: Agent的源代码包含:

  # A list of hooks to call after retrieving a response.  Hooks are called with
  # the agent and the response returned.
  attr_reader :post_connect_hooks

  # A list of hooks to call before making a request.  Hooks are called with
  # the agent and the request to be performed.
  attr_reader :pre_connect_hooks

  # A list of hooks to call to handle the content-encoding of a request.
  attr_reader :content_encoding_hooks

所以它看起来甚至看起来都没有调用正确的钩子。

这是我开始工作的一个例子:

require 'mechanize'

a = Mechanize.new

p a.content_encoding_hooks

func = lambda do |a, uri, resp, body_io| 
  puts body_io.read
  puts "The Content-Encoding is: #{resp['Content-Encoding']}"

  if resp['Content-Encoding'].to_s == 'UTF-8'
    resp['Content-Encoding'] = 'none'
  end

  puts "The Content-Encoding is now: #{resp['Content-Encoding']}"
end

a.content_encoding_hooks << func

a.get(
  'http://localhost:8080/cgi-bin/myprog.rb',
  [],
  nil,
  "Accept-Encoding" => 'gzip, deflate'  #This is what Firefox always uses
)

myprog.rb:

#!/usr/bin/env ruby

require 'cgi'

cgi = CGI.new('html3')

headers = {
  "type" => 'text/html',
  "Content-Encoding" => "UTF-8",
}

cgi.out(headers) do
  cgi.html() do
    cgi.head{ cgi.title{"Content-Encoding Test"} } +
    cgi.body() do
      cgi.div(){ "The Accept-Encoding was: #{cgi.accept_encoding}" }
    end
  end
end

--output:--
[]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD><TITLE>Content-Encoding Test</TITLE></HEAD><BODY><DIV>The Accept-Encoding was: gzip, deflate</DIV></BODY></HTML>
The Content-Encoding is: UTF-8
The Content-Encoding is now: none