Cách gửi dữ liệu json trong yêu cầu Http bằng NSURLRequest


80

Tôi là người mới đối với mục tiêu-c và tôi đang bắt đầu nỗ lực rất nhiều vào yêu cầu / phản hồi kể từ gần đây. Tôi có một ví dụ hoạt động có thể gọi một url (thông qua http GET) và phân tích cú pháp json được trả về.

Dưới đây là ví dụ làm việc

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
  NSLog([NSString stringWithFormat:@"Connection failed: %@", [error description]]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [connection release];
  //do something with the json that comes back ... (the fun part)
}

- (void)viewDidLoad
{
  [self searchForStuff:@"iPhone"];
}

-(void)searchForStuff:(NSString *)text
{
  responseData = [[NSMutableData data] retain];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.whatever.com/json"]];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

Câu hỏi đầu tiên của tôi là - liệu cách tiếp cận này có mở rộng quy mô không? Hoặc đây không phải là không đồng bộ (nghĩa là tôi chặn chuỗi giao diện người dùng trong khi ứng dụng đang chờ phản hồi)

Câu hỏi thứ hai của tôi là - làm thế nào tôi có thể sửa đổi phần yêu cầu của điều này để thực hiện ĐĂNG thay vì GET? Nó chỉ đơn giản là để sửa đổi HttpMethod như vậy?

[request setHTTPMethod:@"POST"];

Và cuối cùng - làm cách nào để thêm một tập hợp dữ liệu json vào bài đăng này dưới dạng một chuỗi đơn giản (ví dụ)

{
    "magic":{
               "real":true
            },
    "options":{
               "happy":true,
                "joy":true,
                "joy2":true
              },
    "key":"123"
}

Cảm ơn bạn trước


Câu trả lời:


105

Đây là những gì tôi làm (xin lưu ý rằng JSON đi đến máy chủ của tôi cần phải là một từ điển có một giá trị (từ điển khác) cho key = question..ie {: question => {dictionary}}):

NSArray *objects = [NSArray arrayWithObjects:[[NSUserDefaults standardUserDefaults]valueForKey:@"StoreNickName"],
  [[UIDevice currentDevice] uniqueIdentifier], [dict objectForKey:@"user_question"],     nil];
NSArray *keys = [NSArray arrayWithObjects:@"nick_name", @"UDID", @"user_question", nil];
NSDictionary *questionDict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:questionDict forKey:@"question"];

NSString *jsonRequest = [jsonDict JSONRepresentation];

NSLog(@"jsonRequest is %@", jsonRequest);

NSURL *url = [NSURL URLWithString:@"https://xxxxxxx.com/questions"];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];

[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody: requestData];

NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
 receivedData = [[NSMutableData data] retain];
}

Sau đó, dữ liệu đã nhận được xử lý bởi:

NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [jsonString JSONValue];
NSDictionary *question = [jsonDict objectForKey:@"question"];

Điều này không rõ ràng 100% và sẽ mất một số lần đọc lại, nhưng mọi thứ sẽ ở đây để bạn bắt đầu. Và từ những gì tôi có thể nói, điều này là không đồng bộ. Giao diện người dùng của tôi không bị khóa trong khi các cuộc gọi này được thực hiện. Hy vọng rằng sẽ giúp.


Mọi thứ đều ổn ngoại trừ dòng này [dict objectForKey: @ "user_question"], nil]; - dict không được khai báo trong mẫu của bạn. Đây chỉ là một từ điển đơn giản hay một cái gì đó đặc biệt?
Toran Billups

1
Xin lỗi vì điều đó. Vâng, "dict" chỉ là một từ điển đơn giản mà tôi tải từ tài liệu của người dùng iOS.
Mike G

19
Đây là sử dụng NSDictionaryphương pháp thể hiện JSONRepresentation. Tôi có thể đề nghị tôi sử dụng NSJSONSerializationphương thức lớp dataWithJSONObject, thay vì json-framework .
Rob

Sẽ hiệu quả hơn khi chuyển đổi NSUInteger thành NSString thông qua NSNumber như [[NSNumber numberWithUnsignedInt:requestData.length] stringValue].
tôn trọngMã mã

1
@MikeG Đã sửa lỗi tồn tại lâu dài và cho đến nay chưa được chú ý trong mẫu mã. Xin lỗi, vì đã chỉnh sửa bài đăng của bạn;)
CouchDeveloper

7

Tôi đã đấu tranh với điều này trong một thời gian. Chạy PHP trên máy chủ. Mã này sẽ đăng json và nhận json trả lời từ máy chủ

NSURL *url = [NSURL URLWithString:@"http://example.co/index.php"];
NSMutableURLRequest *rq = [NSMutableURLRequest requestWithURL:url];
[rq setHTTPMethod:@"POST"];
NSString *post = [NSString stringWithFormat:@"command1=c1&command2=c2"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
[rq setHTTPBody:postData];
[rq setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:rq queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
 {
     if ([data length] > 0 && error == nil){
         NSError *parseError = nil;
         NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
         NSLog(@"Server Response (we want to see a 200 return code) %@",response);
         NSLog(@"dictionary %@",dictionary);
     }
     else if ([data length] == 0 && error == nil){
         NSLog(@"no data returned");
         //no data, but tried
     }
     else if (error != nil)
     {
         NSLog(@"there was a download error");
         //couldn't download

     }
 }];

1
content type = "application / x-www-form-urlencoded" đã thực hiện thủ thuật. Cảm ơn
SamChen

Câu trả lời hay đấy. Tôi đã từng "application / json" trong trường hợp của tôi
Gajendra K Chauhan

6

Tôi muốn đề xuất sử dụng ASIHTTPRequest

ASIHTTPRequest là một trình bao bọc dễ sử dụng xung quanh API CFNetwork giúp làm cho một số khía cạnh tẻ nhạt hơn của việc giao tiếp với máy chủ web trở nên dễ dàng hơn. Nó được viết bằng Objective-C và hoạt động trong cả ứng dụng Mac OS X và iPhone.

Nó phù hợp thực hiện các yêu cầu HTTP cơ bản và tương tác với các dịch vụ dựa trên REST (GET / POST / PUT / DELETE). Lớp con ASIFormDataRequest được bao gồm giúp dễ dàng gửi dữ liệu POST và tệp bằng cách sử dụng dữ liệu đa phần / biểu mẫu.


Xin lưu ý rằng tác giả ban đầu đã ngừng với dự án này. Xem bài đăng tiếp theo để biết lý do và lựa chọn thay thế: http://allights-i.com/%5Brequest_release%5D ;

Cá nhân tôi là một fan hâm mộ lớn của AFNetworking


Duh, tôi không. Lấy làm tiếc.
Almo

3

Hiện tại, hầu hết các bạn đã biết điều này, nhưng tôi đăng bài này, chỉ trong trường hợp, một số bạn vẫn đang gặp khó khăn với JSON trong iOS6 +.

Trong iOS6 trở lên, chúng tôi có Lớp NSJSONSerialization nhanh và không phụ thuộc vào việc bao gồm các thư viện "bên ngoài".

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:[resultStr dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; 

Đây là cách iOS6 trở lên hiện có thể phân tích cú pháp JSON một cách hiệu quả. Việc sử dụng SBJson cũng là triển khai trước ARC và kéo theo những vấn đề đó nếu bạn đang làm việc trong môi trường ARC.

Tôi hi vọng cái này giúp được!


2

Đây là một bài viết tuyệt vời bằng cách sử dụng Restkit

Nó giải thích về việc tuần tự hóa dữ liệu lồng nhau thành JSON và đính kèm dữ liệu vào một yêu cầu HTTP POST.


2

Vì chỉnh sửa của tôi cho câu trả lời của Mike G để hiện đại hóa mã đã bị từ chối 3 đến 2 như

Chỉnh sửa này nhằm mục đích đề cập đến tác giả của bài đăng và không có ý nghĩa như một chỉnh sửa. Đáng lẽ nó phải được viết dưới dạng một bình luận hoặc một câu trả lời

Tôi đăng lại bản chỉnh sửa của mình dưới dạng một câu trả lời riêng ở đây. Chỉnh sửa này loại bỏ sự JSONRepresentationphụ thuộc NSJSONSerializationnhư nhận xét của Rob với 15 phiếu ủng hộ cho thấy.

    NSArray *objects = [NSArray arrayWithObjects:[[NSUserDefaults standardUserDefaults]valueForKey:@"StoreNickName"],
      [[UIDevice currentDevice] uniqueIdentifier], [dict objectForKey:@"user_question"],     nil];
    NSArray *keys = [NSArray arrayWithObjects:@"nick_name", @"UDID", @"user_question", nil];
    NSDictionary *questionDict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:questionDict forKey:@"question"];

    NSLog(@"jsonRequest is %@", jsonRequest);

    NSURL *url = [NSURL URLWithString:@"https://xxxxxxx.com/questions"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                 cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


    NSData *requestData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil]; //TODO handle error

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody: requestData];

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    if (connection) {
     receivedData = [[NSMutableData data] retain];
    }

Sau đó, dữ liệu đã nhận được xử lý bởi:

NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSDictionary *question = [jsonDict objectForKey:@"question"];

0

Dưới đây là một ví dụ cập nhật đang sử dụng NSURLConnection + sendAsynchronousRequest: (10.7+, iOS 5+), Yêu cầu "Đăng" vẫn giống với câu trả lời được chấp nhận và được bỏ qua ở đây để rõ ràng:

NSURL *apiURL = [NSURL URLWithString:
    [NSString stringWithFormat:@"http://www.myserver.com/api/api.php?request=%@", @"someRequest"]];
NSURLRequest *request = [NSURLRequest requestWithURL:apiURL]; // this is using GET, for POST examples see the other answers here on this page
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
     if(data.length) {
         NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
         if(responseString && responseString.length) {
             NSLog(@"%@", responseString);
         }
     }
}];

câu hỏi về POST
ahmad

2
không, phần đầu tiên của câu hỏi là về tính không đồng bộ và không có câu trả lời nào ở đây trả lời điều đó. Chúc mừng cho người ủng hộ.
auco

0

Bạn có thể thử mã này để gửi chuỗi json

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:ARRAY_CONTAIN_JSON_STRING options:NSJSONWritin*emphasized text*gPrettyPrinted error:NULL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *WS_test = [NSString stringWithFormat:@"www.test.com?xyz.php&param=%@",jsonString];
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.