实际上,所有先前的答案都至少包含一些不准确之处,对于 TextFields 中用户提供的文本的许多常见值,它们无法与服务器正确通信
stringByAddingPercentEscapesUsingEncoding:percent 转义所有不是有效 URL 字符的字符。此方法应该对整个 URL 应用一次。
先前的答案声称它的stringByAddingPercentEscapesUsingEncoding:工作方式类似于许多脚本语言中的 URL 构建类,您不应将其应用于整个 URL 字符串,但事实并非如此。&任何人都可以通过检查其输出中未转义的 s 和s来轻松验证这一点?。因此,适用于整个字符串是可以的,但仅适用于您的“动态”url 内容是不够的。
前面的答案是正确的,因为您必须对进入 CGI 查询字符串的名称和值做更多的工作。由于 CGI 由 RFC3875 指定,这通常称为 RFC3875 百分比转义。它确保您的名称和值不包含有效的 URL 字符但在 URL 的其他部分很重要的字符(;、?、:、@、&、=、$、+、{、}、<、>和,)
然而,完成对整个字符串执行纯 URL 百分比转义以确保字符串中的所有字符都是有效的 URL 字符也是非常重要的。虽然您的示例中没有,但通常字符串的“静态”部分中可能存在无效 URL 字符的字符,因此您也需要转义这些字符。
不幸的是,NSString它没有给我们逃避 RFC3875 重要字符的能力,所以我们必须深入研究CFString这样做。显然使用CFString是一种痛苦,所以我通常会像这样添加Category一个NSString:
@interface NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding;
@end
@implementation NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding {
CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding);
NSString *rfcEscaped = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)self,
NULL,
(CFStringRef)@";/?:@&=$+{}<>,",
cfEncoding);
return [rfcEscaped autorelease];
}
@end
有了这个Category,原始问题可以通过以下方式正确解决:
NSString *urlEscapedBase = [@"http://server.com/file.php" stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedName = [nameField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedTags = [tagsField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedEntry = [dreamEntry.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *urlStr = [NSString stringWithFormat:@"%@?name=%@&tags=%@&entry=%@",
urlEscapedBase,
rfcEscapedName,
rfcEscapedTags,
rfcEscapedEntry];
NSURL *url = [NSURL URLWithString:urlStr];
这有点变重,只是更清楚。另请注意,提供给的变量列表stringWithFormat:不应nil终止。格式字符串描述了应该跟随它的变量的精确数量。此外,从技术上讲,查询字符串名称(名称、标签、条目等)的字符串应该stringByAddingPercentEscapesUsingEncoding:理所当然地运行,但在这个小示例中,我们可以很容易地看到它们不包含无效的 URL 字符。
要了解前面的解决方案为什么不正确,假设用户输入的文本dreamEntry.text包含一个&,这并非不可能。使用以前的解决方案,当服务器获取该文本时,该字符后面的所有文本都将丢失,因为未转义的 & 符号将被服务器解释为该查询字符串对的值部分的结尾。