После примерно недели исследований без решения, я сдаюсь и прошу вас, ребята, предложения.
Мне нужен один и тот же php-скрипт для одинаковой обработки POST-запросов, независимо от их происхождения, будь то простая форма HTML или приложение для iOS. JSON не задействован.
Выпуск: Некоторые символы теряются, когда отправителем POST является приложение для iOS. В этот момент я бы сказал, что не знаю, почему он так себя ведет. Очевидно, веб-браузер корректно экранирует все символы при создании запроса POST, а мой код obj-c — нет.
В коде target-c вы можете увидеть 5 предварительных предположений, которые я сделал, с небольшим примечанием того, что пошло не так.
Я очень надеюсь, что вы можете помочь
файл tester.php:
<?php
header('Content-Type: text/html; charset=utf-8');
if (isset($_POST['email']))
{
echo "email: " . $_POST['email'];
echo "\n";
echo "password: " . $_POST['password'];
}
else
{
?>
<form method="post">
<input type="text" id="email" name="email" value="切换到中文@gmail.com" />
<br>
<input type="text" id="password" name="password" value="&+=/切/().%&" />
<br>
<input type="submit" />
</form>
<?php
}
Objectice-c HTTP POST выполнение:
// Get values
NSString *email = @"切换到中文@gmail.com";
NSString *password = @"&+=/切/().%&";
NSLog(@"Before: %@ and %@", email, password);
// Escape tentative 1: fails: % disappears
//email = [email stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
//password = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
// Escape tentative 2: failed: % disappears, + becomes a space, who knows what else
// email = [email stringByReplacingOccurrencesOfString: @"&" withString: @"%26"];
// password = [password stringByReplacingOccurrencesOfString: @"&" withString: @"%26"];
// Escape tentative 3: % disappears
// NSString *charactersToEscape = @"!*'();:@&=+$,/?%#[]\" ";
// NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
// email = [email stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
// password = [password stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
// Escape tentative 4: % disappears
/*CFStringRef cf_email = (__bridge CFStringRef)(email);
CFStringRef cf_password = (__bridge CFStringRef)(password);
email = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
cf_email,
NULL,
CFSTR("%:/?#[]@!$&'()*+,;="),
kCFStringEncodingUTF8));
password = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
cf_password,
NULL,
CFSTR("%:/?#[]@!$&'()*+,;="),
kCFStringEncodingUTF8));*/
// Escape tentative 5: password becomes "(null)"/*email = [email stringByReplacingOccurrencesOfString: @"%" withString: @"%25"];
email = [email stringByReplacingOccurrencesOfString: @"&" withString: @"%26"];
email = [email stringByReplacingOccurrencesOfString: @"+" withString: @"%2b"];password = [password stringByReplacingOccurrencesOfString: @"%" withString: @"%25"];
password = [password stringByReplacingOccurrencesOfString: @"&" withString: @"%26"];
password = [password stringByReplacingOccurrencesOfString: @"+" withString: @"%2b"];*/// Execute HTTP request
NSString *postData = [NSString stringWithFormat:@"email=%@&password=%@", email, password];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/tester.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPBody = [postData dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Print response
NSLog([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
[postDataTask resume];
Результат, если я использую форму HTML (именно то, что я ввел в форму):
email: 切换到中文@gmail.com password: &+=/切/().%&
Что я получаю из объективного кода c (некоторые символы исчезают), одного из последних тестов:
2016-09-29 21:28:59.519 test[44752:2438179] Before: 切换到中文@gmail.com (15) and &+=/切/().%& (11)
2016-09-29 21:28:59.705 test[44752:2438721] email: 切换到中文@gmail.com password: &+=/切/().&
Это способ, которым я делаю. Это работало довольно хорошо со всем, что я пробовал. Во-первых, вам нужно добавить эту функцию в NSString:
@implementation NSString (NSStringWebStructure)
-(NSString*)stringToWebStructure
{
NSString* webString = [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
webString = [webString stringByReplacingOccurrencesOfString:@"&" withString:@"%26"];
webString = [webString stringByReplacingOccurrencesOfString:@"?" withString:@"%3F"];
return webString;
}
@end
Теперь вам нужны функции запроса:
-(NSString*)launchURL:(NSURL*)url withPostString:(NSString*)post
{
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (response.statusCode >= 200 && response.statusCode < 300)
{
NSString *responseData = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
if (responseData.length > 0) return responseData;
}
else if (error) return [error description];
return nil;
}
-(NSString*)launchURL:(NSURL*)url withPostValues:(NSDictionary*)postDict
{
NSArray* postKeys = postDict.allKeys;
NSMutableArray* postLines = [[NSMutableArray alloc] init];
for (NSString* key in postKeys)
{
[postLines addObject:[NSString stringWithFormat:@"%@=%@",key,[postDict[key] stringToWebStructure]]];
}
return [self launchURL:url withPostString:[postLines componentsJoinedByString:@"&"]];
}
И, учитывая ваш пример, вам просто нужно сделать это:
NSString *email = @"切换到中文@gmail.com";
NSString *password = @"&+=/切/().%&";
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/tester.php"];
NSDictionary* postValues = @{@"email":email, @"password": password};
NSString* response = [self launchURL:url withPostValues: postValues];
NSLog(@"%@",response);
stringByAddingPercentEscapesUsingEncoding:
устарел в macOS 10.11, но если вы собираетесь поддерживать старые версии macOS, как я, это функциональный метод (протестирован с macOS 10.6 до macOS 10.12).
Других решений пока нет …