如何从表单编码的字符串中获得漂亮的打印

how to get pretty printing from a form-encoded string

好先生。 我如何强制 request.body (或任何其他非 JSON 字符串)以漂亮的多行 JSON 或 yaml 样式打印出来?

我见过将此类字符串转换为真实字符串的奇特方法JSON,但希望避免使用另一种方法。

  def request_token_from_google
    uri = URI.parse('https://www.googleapis.com/oauth2/v3/token')
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    request = Net::HTTP::Post.new(uri.request_uri)
    request.set_form_data(self.to_params)
    puts "request body is"
    puts request.body.to_yaml # doesn't work
    puts request.body.to_json # doesn't work
    http.request(request)
  end

这个问题:

ap "request body is #{request.body.to_json}"

...而您的其他尝试是您正在尝试漂亮地打印已经是字符串的内容。 awesome_print(和 inspect 及其同类)的目的是获取一个具有某种结构的对象并将其打印出来,这样您就可以看到它的结构,但是字符串没有结构——它只是字符,性格,性格。当你给 awesome_print 一个像 "request body is {"foo":... 这样的字符串时,它无法知道 "is."

之后的部分有什么特别之处

如果你有一个有结构的对象,解决方案是直接把它给awesome_print:

puts "request body is:"
ap my_hash_or_array

不幸的是,在这种情况下它无济于事,因为 request.body 也只是一个字符串——它是形式编码的数据,就像这样(从 Wikipedia 偷来的):

Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21

就像"request body is..."的例子一样,awesome_print无法知道这有什么特别之处。您可以做的一件非常简单的事情就是在每个 key/value 对之间放置一个换行符:

body = "Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21"

puts "Request body is:"
puts body.gsub("&", "\n  &")
# => Request body is:
#    Name=Jonathan+Doe
#      &Age=23
#      &Formula=a+%2B+b+%3D%3D+13%25%21

这有一个缺点,即值仍然是百分比编码的,正如您在 Formula 中看到的那样。如果这是一个问题,您可以使用 CGI.parseRack::Utils.parse_query 来解析表单数据,这两者在 Rails 中都可用。它们都 return 一个可以给 awesome_print 的哈希,但格式略有不同(CGI return 将所有值作为数组,Rack::Utils 仅当它们在 "array" 格式,例如 foo[]=1&foo[]=2)。这是 Rack::Utils(您只需想象输出是彩色的):

puts "Request body is:"
ap Rack::Utils.parse_query(body)
# => Request body is:"
#    {
#           "Name" => "Jonathan Doe",
#            "Age" => "23",
#        "Formula" => "a + b == 13%!"
#    }

最后,一些不请自来的建议:写入 STDOUT 的 putsap 在开发中往往工作正常,因为 Rails' 记录器也在写入 STDOUT,所以您会在与 Rails 服务器日志相同的终端 window 中看到 puts 输出。然而,在生产中,写入 STDOUT 的数据可能不会写入任何地方的文件,即使是,如果您在某个时候更改 Rails.logger 配置,ap's output may still be going somewhere else. What you probably want is to use Rails' 记录器putsap,因此您可以确保所有输出都到达同一个地方。幸运的是,awesome_print 为每个对象添加了一个 awesome_inspect 方法,return 与您使用 ap 时看到的漂亮字符串相同,因此您仍然可以使用 awesome_print Rails.logger:

body_inspect = Rack::Utils.parse_query(body).awesome_inspect
Rails.logger.info("Request body is:\n#{body_inspect}")