实际上,所有先前的答案都至少包含一些不准确之处,对于 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
包含一个&
,这并非不可能。使用以前的解决方案,当服务器获取该文本时,该字符后面的所有文本都将丢失,因为未转义的 & 符号将被服务器解释为该查询字符串对的值部分的结尾。