如何在Rails中输出JSON而不转义反斜杠

Gre*_*g W 13 ruby json ruby-on-rails

我需要以一种不同寻常的格式为客户输出一些JSON.我的应用程序是用Rails 5编写的.

期望的JSON:

{
  "key": "\/Date(0000000000000)\/"
}
Run Code Online (Sandbox Code Playgroud)

时间戳值需要\/在字符串的开头和结尾都有.据我所知,这似乎是.NET服务中常用的一种格式.我试图让斜线正确输出.

我通过单个控制器操作将问题简化为vanilla Rails 5应用程序.到目前为止,我能想到的逃逸的所有排列都失败了.

def index
  render json: {
    a: '\/Date(0000000000000)\/',
    b: "\/Date(0000000000000)\/",
    c: '\\/Date(0000000000000)\\/',
    d: "\\/Date(0000000000000)\\/"
  }
end
Run Code Online (Sandbox Code Playgroud)

其中输出如下:

{
    "a": "\\/Date(0000000000000)\\/",
    "b": "/Date(0000000000000)/",
    "c": "\\/Date(0000000000000)\\/",
    "d": "\\/Date(0000000000000)\\/"
}
Run Code Online (Sandbox Code Playgroud)

为了便于讨论,假设格式不能改变,因为它是由第三方控制的.

我已经向Github上传了一个测试应用程序来演示这个问题.https://github.com/gregawoods/test_app_ignore_me

Gre*_*g W 11

在与同事进行了一些头脑风暴之后(感谢@TheZanke),我们找到了一个可以使用本机Rails JSON输出的解决方案.

警告:此代码会覆盖ActiveSupport中的某些核心行为.使用风险自负,并进行明智的单元测试!

我们将其跟踪到ActiveSupport中的JSON编码.所有字符串最终都是通过ActiveSupport::JSON.encode.我们需要找到一种方法来短路该逻辑并简单地返回未编码的字符串.

首先,我们扩展了此处EscapedString#to_json方法.

module EscapedStringExtension
  def to_json(*)
    if starts_with?('noencode:')
      "\"#{self}\"".gsub('noencode:', '')
    else
      super
    end
  end
end

module ActiveSupport::JSON::Encoding
  class JSONGemEncoder
    class EscapedString
      prepend EscapedStringExtension
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后在控制器中我们noencode:为json哈希添加一个标志.这告诉我们的版本to_json不要做任何额外的编码.

def index
  render json: {
     a: '\/Date(0000000000000)\/',
     b: 'noencode:\/Date(0000000000000)\/',
   }
end
Run Code Online (Sandbox Code Playgroud)

渲染的输出显示b给我们想要的东西,同时a保留标准行为.

$ curl http://localhost:3000/sales/index.json
{"a":"\\/Date(0000000000000)\\/","b":"\/Date(0000000000000)\/"}
Run Code Online (Sandbox Code Playgroud)


the*_*Man 7

冥想:

Ruby在双引号和单引号字符串中处理相同的正斜杠.

"/"   # => "/"
'/'   # => "/"
Run Code Online (Sandbox Code Playgroud)

在双引号字符串中"\/"意味着\转义以下字符.因为/没有转义的等价物,所以会产生一个正斜杠:

"\/"  # => "/"
Run Code Online (Sandbox Code Playgroud)

在所有情况下的单引号字符串中只有一个意味着有一个反斜杠后跟字符的文字值.那个例子就是你想要代表一个反斜杠本身:

'\/'  # => "\\/"

"\\/" # => "\\/"
'\\/' # => "\\/"
Run Code Online (Sandbox Code Playgroud)

学习这是处理语言中的字符串最令人困惑的部分之一,这不仅限于Ruby,它是从编程的早期开始的.

了解以上内容:

require 'json'

puts JSON[{ "key": "\/value\/" }] 
puts JSON[{ "key": '/value/' }]
puts JSON[{ "key": '\/value\/' }]

# >> {"key":"/value/"}
# >> {"key":"/value/"}
# >> {"key":"\\/value\\/"}
Run Code Online (Sandbox Code Playgroud)

您应该能够更好地了解您在结果和上面的JSON输出中看到的内容.

我认为这个规则最初是为C创建的,因此" 在C中转义序列 "可能有所帮助.

  • 好吧,如果你在代码中生成了值,只需使用单引号来定义文字,它就会变得正确.如果客户不理解,您必须将它们指向文档.或者额外收取辅导费用. (3认同)