NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义

Posted

技术标签:

【中文标题】NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义【英文标题】:NSJSONSerialization serialization of a string containing forward slashes / and HTML is escaped incorrectly 【发布时间】:2013-04-03 17:55:42 【问题描述】:

我正在尝试将一些简单的 html 转换为 JSON 对象中的字符串值,但我无法让字符串编码不转义 NSJSONSerialization 中的字符串。

示例...我有一个包含一些基本 HTML 文本的字符串:

NSString *str = @"<html><body><p>Samples / Text</p></body></html>";

期望的结果是带有 HTML 作为值的 JSON:


    "Title":"My Title",
    "Instructions":"<html><body><p>Samples / Text</p></body></html>"

我正在使用标准技术将 NSDictionary 转换为包含 JSON 的 NSString:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:str forKey:@"Instructions"];
[dict setObject:@"My Title" forKey:@"Title"];

NSError *err;
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&err];
NSString *resultingString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", resultingString);

此方法生成的 JSON 是有效的,但是 HTML 中的所有正斜杠都被转义了:


    "Title":"My Title",
    "Instructions":"<html><body><p>Samples \/ Text<\/p><\/body><\/html>"

这会在说明 JSON 字符串中创建无效的 HTML。

我想坚持使用 NSJSONSerialization,因为我们在框架中的其他任何地方都使用它,并且在切换到非 Apple 库之前我已经被烧毁了,因为它们被取消支持。我已经尝试了许多不同的字符串编码,它们都避开了尖括号。

显然 \/ 是 javascript 中 / 字符的有效表示,这就是转义正斜杠的原因(甚至 *** 文本编辑器也转义了它)。看: escaping json string with a forward slash? 还有JSON: why are forward slashes escaped?。我只是不希望它这样做,而且似乎没有办法阻止 ios 在序列化时转义字符串值中的正斜杠。

【问题讨论】:

另一个不使用 NSJSONSerialization 的好理由,我想。人们总是可以扫描数据并将相邻的“\/”字符替换为“/”,但有点乱。 这就是我现在正在做的事情,感觉就像是 hack。不幸的是,我目前使用的所有第三方 iOS 框架都在原作者感到无聊或忙碌后被取消支持。 我们仍在使用 SBJSON。最坏的情况是你可以自己写——实际上只有大约 2K 行代码,只要你不要太花哨。 序列化完全有效。任何体面的反序列化器都可以毫无问题地取回原始字符串。 【参考方案1】:

我相信NSJSONSerialization 在编码 HTML 方面的行为符合设计。

如果您查看一些关于在 JSON 中编码 HTML 的问题(1、2),您会看到答案总是提到转义正斜杠。

JSON 不需要转义正斜杠,但 HTML 不允许 javascript 字符串包含 &lt;/,因为它可能与 &lt;SCRIPT&gt; 标记的结尾混淆。

查看答案here、here 和最直接的w3.org HTML4 Appendix,其中在B.3.2 Specifying non-HTML data 中声明

ILLEGAL EXAMPLE: 
The following script data incorrectly contains a "</" sequence (as part of "</EM>") before the SCRIPT end tag:

<SCRIPT type="text/javascript">
  document.write ("<EM>This won't work</EM>")
</SCRIPT>

虽然这种行为可能会给您带来问题,但 NSJSONSerialisation 只是在按照古老的编码 HTML 数据以用于&lt;SCRIPT&gt; 标记的规则进行游戏。

【讨论】:

【参考方案2】:

这是我的 AFJSONRequestSerializer 子类,用于在生成的 JSON 中删除 / 符号之前的 \;如果你使用 AFNetworking 会很方便

class SanitizedAFJSONRequestSerializer: AFJSONRequestSerializer

    override func requestBySerializingRequest(request: NSURLRequest!, withParameters parameters: AnyObject!, error: NSErrorPointer) -> NSURLRequest!
    
        var request = super.requestBySerializingRequest(request, withParameters: parameters, error: error)

        if let jsonData = request.HTTPBody
        
            if let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as? String
            
                let sanitizedString = jsonString.stringByReplacingOccurrencesOfString("\\/", withString: "/", options: NSStringCompareOptions.CaseInsensitiveSearch, range:nil) as NSString

                println("sanitized json string: \(sanitizedString)")

                var mutableRequest = request.mutableCopy() as! NSMutableURLRequest
                mutableRequest.HTTPBody = sanitizedString.dataUsingEncoding(NSUTF8StringEncoding)
                request = mutableRequest
            
        

        return request
    

【讨论】:

【参考方案3】:

仅限 iOS 13: 如果您不担心产生无效的 HTML 序列(如 this answer 中所述),您可以通过将选项 NSJSONWritingWithoutEscapingSlashes 传递给序列化程序来禁用正斜杠转义。

例子:

jsonData = [NSJSONSerialization dataWithJSONObject:batchUpdates
                                           options:NSJSONWritingWithoutEscapingSlashes
                                             error:nil];

【讨论】:

以上是关于NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义的主要内容,如果未能解决你的问题,请参考以下文章

如何处理包含正斜杠 (/) 的请求?

如何处理包含正斜杠(/)的请求?

在 Windows 批处理文件中将反斜杠更改为正斜杠

包含斜杠的 SQL Server 2012 查询字符串

你如何 grep 一个包含斜杠的字符串?

bash测试 - 匹配正斜杠