正如Peter所说,content-type头部只是一个对发送内容的暗示。在服务器端,您可以设置任何内容类型并发送任何字节序列,这可能无效。
我曾遇到处理不正确的UTF-8数据(包括ISO-8859-1(Latin-1)字符(例如法语重音符号))的完全相同问题。
阅读
维基百科关于UTF-8以了解此问题及如何处理编码错误是值得的。
事实上,
NSString initWithData:encoding:
的严格实现仅在发生解码错误时返回nil。(与Java不同,后者使用替换字符)
Peter的将大部分UTF-8数据转换为Latin-1的解决方案并不能令我满意。
(所有UTF-8字符都变得不正确,仅仅因为有一个Latin 1异常字符)
最好的选择当然是在服务器端进行修复,但我没有这方面的责任......
因此,我深入研究,并找到了一种使用GNU libiconv C库(可在OSX和iOS上使用)的解决方案。
原则上是使用iconv删除非UTF-8无效字符(例如,“prété”将变为“prt”)。
这是一个示例代码,相当于命令行iconv -c -f UTF-8 -t UTF-8 invalid.txt > cleaned.txt
#include "iconv.h"
- (NSData *)cleanUTF8:(NSData *)data {
iconv_t cd = iconv_open("UTF-8", "UTF-8");
int one = 1;
iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, &one);
size_t inbytesleft, outbytesleft;
inbytesleft = outbytesleft = data.length;
char *inbuf = (char *)data.bytes;
char *outbuf = malloc(sizeof(char) * data.length);
char *outptr = outbuf;
if (iconv(cd, &inbuf, &inbytesleft, &outptr, &outbytesleft)
== (size_t)-1) {
NSLog(@"this should not happen, seriously");
return nil;
}
NSData *result = [NSData dataWithBytes:outbuf length:data.length - outbytesleft];
iconv_close(cd);
free(outbuf);
return result;
}
然后,生成的
NSData
可以使用
NSUTF8StringEncoding
安全地解码。
请注意,最新的iconv也允许使用回退方法,方法是使用:
iconvctl(cd, ICONV_SET_FALLBACKS, &fallbacks);
通过在 Unicode 错误时使用回退,您可以使用替换字符或更好的方式尝试另一种编码。在我的情况下,当 UTF-8 失败时,我成功地回退到 LATIN-1,这导致了 99% 的正向转换。查看 iconv 源代码以理解它。