对不起,这个新问题,但是我在这个问题上撕裂了我的头发.我可以通过像FireFox的POSTER这样的程序成功地将数据发布到我的端点URL.但是,我正在尝试将相同的JSON数据从我的应用程序发布到我的端点URL(Drupal services push_notifications终点),并且由于某种原因它不会成功POST.这是我正在使用的代码:
ViewController.m
NSString *urlString1 = @"http://app.com/endpoint001/push_notifications";
NSDictionary *jsonBodyDict = @{@"token":postDeviceID, @"type":@"ios"};
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];
// watch out: error is nil here, but you never do that in production code. Do proper checks!
NSString *urlString2 = [NSString stringWithFormat:@"http://app.com/endpoint001/push_notifications?token=%@&type=%@",
postDeviceID,@"ios"];
NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = @"POST";
// for alternative 1:
[request setURL:[NSURL URLWithString:urlString1]];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPBody:jsonBodyData];
[request addValue:csrfToken forHTTPHeaderField:@"X-CSRF-Token"];
// for alternative 2:
[request setURL:[NSURL URLWithString:urlString2]];
// no body needed, though that ultimately depends on your server. Also, I didn't test this for lack of a backend :)
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSLog(@"Yay, done! Check for errors in response!");
NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
NSLog(@"The response is: %@", asHTTPResponse);
// set a breakpoint on the last NSLog and investigate the response in the debugger
// if you get data, you can inspect that, too. If it's JSON, do one of these:
NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
// or
NSArray *forJSONArray = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
NSLog(@"One of these might exist - object: %@ \n array: %@", forJSONObject, forJSONArray);
}];
[task resume];
Run Code Online (Sandbox Code Playgroud)
注意:我已将此代码放入用户已成功登录后,因此我不确定是否需要启动全新连接?如果会话和CSRF令牌已存在,如何将数据发布到服务器?我的代码应该是什么样的?无论谁回答这个问题都在我的圣诞节清单上... O_O
NSLog响应:
2017-07-17 17:31:11.421281-0700 app[977:206852] Yay, done! Check for errors in response!
2017-07-17 17:31:11.422198-0700 app[977:206852] The response is: <NSHTTPURLResponse: 0x170239b40> { URL: http://app.com/endpoint001/push_notifications?token=9526687d594944513b0wabf704eae3223f0de9bf69136a0aae3ab046863474b1&type=ios } { status code: 401, headers {
"Cache-Control" = "no-cache, must-revalidate";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Tue, 18 Jul 2017 00:14:35 GMT";
Expires = "Sun, 19 Nov 1978 05:00:00 GMT";
Server = Apache;
"Transfer-Encoding" = Identity;
Vary = Accept;
"X-Content-Type-Options" = nosniff;
} }
2017-07-17 17:31:27.172085-0700 app[977:207024] XPC connection interrupted
2017-07-17 17:31:27.172311-0700 app[977:206852] One of these might exist - object: (
"CSRF validation failed"
)
array: (
"CSRF validation failed"
)
Run Code Online (Sandbox Code Playgroud)
汤姆的回答给出了正确的方向,但我发现缺乏描述代码实际上做的事情让你感到困惑.此外,您正在使用弃用的方法NSURLConnection,因此我使用了NSURLSession及其相关类的快速(未经测试)示例.别担心,它基本相同.
话虽这么说,你在原始代码中尝试这种方式的方式让我想知道你是否真的真的发送了一个json体(即你的后端期望)或者说系统依赖于无聊的URL参数.所以我在代码中添加了两种方法:
NSString *postDeviceID = @"something";
NSString *urlString1 = @"http://myurl.com/endpoint01/push_notifications";
NSDictionary *jsonBodyDict = @{@"token":postDeviceID, @"type":@"ios"};
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];
// watch out: error is nil here, but you never do that in production code. Do proper checks!
NSString *urlString2 = [NSString stringWithFormat:@"http://myurl.com/endpoint01/push_notifications?token=%@&type=%@",
postDeviceID,@"ios"];
NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = @"POST";
// for alternative 1:
[request setURL:[NSURL URLWithString:urlString1]];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPBody:jsonBodyData];
// for alternative 2:
[request setURL:[NSURL URLWithString:urlString2]];
// no body needed, though that ultimately depends on your server. Also, I didn't test this for lack of a backend :)
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSLog(@"Yay, done! Check for errors in response!");
NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
NSLog(@"The response is: %@", asHTTPResponse);
// set a breakpoint on the last NSLog and investigate the response in the debugger
// if you get data, you can inspect that, too. If it's JSON, do one of these:
NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
// or
NSArray *forJSONArray = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
NSLog(@"One of these might exist - object: %@ \n array: %@", forJSONObject, forJSONArray);
}];
[task resume];
Run Code Online (Sandbox Code Playgroud)
你的后端也可以支持两种方式,但学习如何构建一个合适的json体总是有帮助的.请注意,Tom的代码让你认为它发布的原因是你似乎误解了它是如何NSURLConnection工作的(除非你排除了你依赖的代码):对象总是以你使用它的方式构造,所以if (conn)总是在YES分支中.这并不意味着连接,即实际加载成功.如果初始化程序nil无法创建实例,则返回初始化程序,而不是有效实例仅依赖于连接到其目标时拒绝的数据.你不会以这种方式得到错误(你需要依赖委托).
我展示的会话方法为您提供了一个完成块,您可以在其中调查服务器响应的内容,以进一步跟踪出错的地方.您可以在那里设置断点并查看错误(nil如果成功),响应中的状态等.
我显然没有运行这个确切的代码,所以原谅任何错别字,但我已经使用这种方法很多加载和发送到我的日常工作的各种后端.一般情况下,它应该工作(更重要的是,让你弄清楚你的后端应该是什么,假设你没有关于它的详细文档).
编辑:
好的,代码注释中的提示可能会产生误导:我打算检查错误的响应.的response对象(也请参阅文档dataTask...一般方法).我添加了一些代码帮助,但请注意,将data对象转换为JSON取决于您的服务器实际传递任何数据的内容.或者它可能有一个奇怪的格式或东西,你需要弄清楚这一点.对于获得POST的简单内容,它可能不提供任何数据,您只需获得有关它是否有效的相关信息response.请注意特别NSHTTPURLResponse的statusCode财产.除非您的服务器做了一些奇怪的事情,否则这是标准定义的HTTP状态代码,应该可以帮助您.例如,如果您在请求中构造主体的方式(jsonBodyDict在我的示例代码中)是错误的(错误的元素名称等),那么您将获得400.
一般来说,你必须明白"错误"的含义并不是那么简单.这些方法根本不能作为错误连接,因此在这些情况下,您将在完成块中获得错误对象.当您的服务器根本不存在或类似情况时,通常就是这种情况.但是,如果您只是无法将预期信息传达给服务器,那么从API的角度来看,这不是错误,并且您没有获得错误对象.您会得到一个有效的回复,上面写着"此请求是错误的".你已经在你的情况下做得很好,因为连接似乎发生并且有效,你还没有发送服务器期望的数据.本response应该给上更多的信息.
为了进一步调试,这将超出这个问题的范围,因为最终我们正在谈论你的特定后端如何表现.如果你无法解决这个问题,你需要给我服务器的凭据,这样我就可以自己测试一下,其他一切都会在我现在猜测.:)我们可以做到这一点,但最好是在聊天中这样做,而不是在已经很久的问题/答案中,呵呵.
所有的答案都很好,但我发布了一个方法,为我正确实施发布JSON数据POST API
POST方法
-(void)postServiceAPI:(NSString*)url andParameters:(NSString *)parameterString andCompletionHandler:(void(^)(NSData *data,NSError *error,BOOL networkError))compilationHandler
{
// Checking the Network availability : You can skip this check
Reachability *netConnectionReach = [Reachability reachabilityWithHostname:@"www.google.com"];
NetworkStatus internetStatus = [netConnectionReach currentReachabilityStatus];
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN))
{
dispatch_async(dispatch_get_main_queue(), ^{
compilationHandler(nil,nil,TRUE);
});
}
else
{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.timeoutIntervalForRequest = 30.0;
configuration.timeoutIntervalForResource = 60.0;
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
_session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *urlStr = [NSURL URLWithString:url];
NSData *postData = [parameterString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlStr
cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
// You can also set " application/json"
// This will solve your problem
[ request setValue:@"Your_Token" forHTTPHeaderField:@"your_key_for_token"];
[request setHTTPBody:postData];
[[_session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (error)
{
dispatch_async(dispatch_get_main_queue(), ^{
compilationHandler(nil,error,nil);
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
compilationHandler(data,nil,nil);
});
}
}]resume];
}
}
Run Code Online (Sandbox Code Playgroud)
用途:
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
[dict setObject:postDeviceID forKey:@"token"];
[dict setObject:@"iOS" forKey:@"type"];
NSData * JsonData =[NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSString *urlStr = @"http://myurl.com/endpoint01/push_notifications"
NSString *parameterJsonString= [[NSString alloc] initWithData:JsonData encoding:NSUTF8StringEncoding];
// If you Don't want to create Dictionary than just send your Parameter JSon what you have made , please make sure if json is correct or not
//parameterJsonString = [NSString stringWithFormat:@"token=%@&type=%@",postDeviceID,@"ios"];
NSLog(@"URL:%@ Request :\n\n %@",urlStr,parameterJsonString);
[self postServiceAPI:urlStr andParameters:parameterJsonString andCompletionHandler:^(NSData *data, NSError *error, BOOL networkError) {
// If Data Retrun By API is not nil
if (data)
{
// Here is your Response
NSDictionary *dicData=[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
}
else
{
// Show Alert When data is Not Recived from API
if (networkError)
{
// No Internet Connection
}
else
{
// Network Error
NSLog(@"Network Error : %@",error.description);
}
}
}];
Run Code Online (Sandbox Code Playgroud)
我希望这能帮到您