На самом деле, все предыдущие ответы содержат, по крайней мере, некоторые неточности, которые для многих общих значений предоставленного пользователем текста в текстовых полях не будут правильно связываться с сервером
stringByAddingPercentEscapesUsingEncoding:
процентов экранирует все символы, которые не являются допустимыми символами 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
. Строка формата описывает точное количество переменных, которые должны следовать за ней. Кроме того, технически строки для имен строк запроса (name, tags, entry, ..) должны проходить через stringByAddingPercentEscapesUsingEncoding:
как само собой разумеющееся, но в этом небольшом примере мы легко видим, что они не содержат недопустимых символов URL.
Чтобы понять, почему предыдущие решения неверны, представьте, что пользовательский ввод текста в dreamEntry.text
содержит &
, что не исключено. В предыдущих решениях весь текст, следующий за этим символом, будет потерян к тому времени, когда сервер получит этот текст, поскольку амперсанд без экранирования будет интерпретироваться сервером как завершение части значения этой пары строк запроса.