【问题标题】:NSData and Uploading Images via POST in iOSNSData 和通过 iOS 中的 POST 上传图像
【发布时间】:2011-12-23 22:47:24
【问题描述】:

我一直在梳理许多关于在 iOS 中通过 POST 上传图像的帖子。尽管有关此主题的信息非常丰富,但我无法正确上传从我的 iPhone 模拟器照片库中获取的 JPEG 数据。 数据一旦在服务器上,就只是一个巨大的十六进制字符串。 NSData 不应该只是一个字节流吗?我不明白所有十六进制是怎么回事,或者为什么这段代码似乎对其他人有效。

这里是有问题的代码:

-(void)uploadWithUserLocationString:(NSString*)userLocation{
NSString *urlString = @"http://some.url.com/post";

// set up the form keys and values (revise using 1 NSDictionary at some point - neater than 2 arrays)
NSArray *keys = [[NSArray alloc] initWithObjects:@"auth",@"text",@"location",nil];
NSArray *vals = [[NSArray alloc] initWithObjects:self.authToken,self.textBox.text,userLocation,nil];

// set up the request object
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];

//Add content-type to Header. Need to use a string boundary for data uploading.
NSString *boundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];

//create the post body
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];

//add (key,value) pairs (no idea why all the \r's and \n's are necessary ... but everyone seems to have them)
for (int i=0; i<[keys count]; i++) {
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@",[vals objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];
}
[body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"image\"\r\n"] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[NSData dataWithData:self.imageData]];
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];

// set the body of the post to the reqeust
[request setHTTPBody:body];

// make the connection to the web
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

NSLog(returnString);
[keys release];
[vals release];
}

感谢您的宝贵时间。

【问题讨论】:

    标签: iphone ios post nsdata nsurlrequest


    【解决方案1】:

    此代码适用于我的应用程序。如果您不使用 ARC,则需要修改代码以释放分配的任何内容。

    // create request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];                                    
    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    [request setHTTPShouldHandleCookies:NO];
    [request setTimeoutInterval:30];
    [request setHTTPMethod:@"POST"];
    
    // set Content-Type in HTTP header
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // post body
    NSMutableData *body = [NSMutableData data];
    
    // add params (all params are strings)
    for (NSString *param in _params) {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"%@\r\n", [_params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
    }
    
    // add image data
    NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
    if (imageData) {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithString:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:imageData];
        [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    }
    
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    // setting the body of the post to the reqeust
    [request setHTTPBody:body];
    
    // set URL
    [request setURL:requestURL];
    

    【讨论】:

    • 您在进行这项工作时遇到过问题吗?这几乎完全是我的代码,我什至像你一样将我的内容类型更改为“图像/JPEG”。也许我的问题是服务器端的,虽然我很肯定它不是。
    • 没问题,此代码在我的应用程序中工作,用于将从 iPhone 相机捕获的 JPG 文件上传到我们的网络服务器。
    • 您能解释一下 filename=\"image.jpg\" 的用途吗?我的代码中没有这个,我认为这是额外的信息,但也许它是必要的?
    • 我想在此处添加有关此代码的评论。回车和换行以及额外的破折号对于这个过程的工作方式都是至关重要的。您必须在正确的位置放置双 CR/LF,并在正确的位置放置额外的破折号。我原以为这只是额外的东西,但它很关键。 XJone 的代码帮助我找出了我错过了一个糟糕的 CR/LF 并且我的上传失败的问题。 +1 为您先生和这个问题。
    • 我不确定。我没有编写服务器端代码,而是发布到专有 API。但是,服务器上的命名对客户端代码没有影响。
    【解决方案2】:

    我希望这段代码能帮助其他人......

    //create request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    
    //Set Params
    [request setHTTPShouldHandleCookies:NO];
    [request setTimeoutInterval:60];
    [request setHTTPMethod:@"POST"];
    
    //Create boundary, it can be anything
    NSString *boundary = @"------VohpleBoundary4QuqLuM1cE5lMwCy";
    
    // set Content-Type in HTTP header
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // post body
    NSMutableData *body = [NSMutableData data];
    
    //Populate a dictionary with all the regular values you would like to send.
    NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
    
    [parameters setValue:param1 forKey:@"param1-name"];
    
    [parameters setValue:param2 forKey:@"param2-name"];
    
    [parameters setValue:param3 forKey:@"param3-name"];
    
    
    // add params (all params are strings)
    for (NSString *param in parameters) {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"%@\r\n", [parameters objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
    }
    
    NSString *FileParamConstant = @"imageParamName";
    
    NSData *imageData = UIImageJPEGRepresentation(imageObject, 1);
    
    //Assuming data is not nil we add this to the multipart form
    if (imageData)
    {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[@"Content-Type:image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:imageData];
        [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    }
    
    //Close off the request with the boundary
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    // setting the body of the post to the request
    [request setHTTPBody:body];
    
    // set URL
    [request setURL:[NSURL URLWithString:baseUrl]];
    
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    
                               NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    
                               if ([httpResponse statusCode] == 200) {
    
                                   NSLog(@"success");
                               }
    
                           }];
    

    【讨论】:

    • 如果我有图像路径dev-demo.info.bh-in-15.webhostbox.net/dv/xyz/ulpoad/post/… 那么我应该把它放在上面的代码中的什么地方
    • @Abhi NSData *imageData = UIImageJPEGRepresentation(imageObject, 1) 替换这一行 .. 从路径加载图像并转换为 nsdata
    • 它令人困惑,请您在答案或评论中更新它
    • @Abhi NSData *imageData = [NSData dataWithContentOfFile:filePath];提供你的文件路径
    【解决方案3】:

    看看 Apple 的 SimpleURLConnections 示例项目。您可以从那里使用 PostController 并进行一些修改。

    但是 - 这并不简单。与上述解决方案的不同之处在于 Apple 使用流将文件流式传输到服务器。这比在上传期间保留编码的图像数据对内存更友好。它也更复杂。

    【讨论】:

      【解决方案4】:
      NSData *imgData = UIImagePNGRepresentation(imgUser.image);
      
      NSString *str=[NSString stringWithFormat:@"%@upload_image",appDelegate.strRoot];
      NSString *urlString = [NSString stringWithFormat:@"%@",str];
      
      NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
      [request setURL:[NSURL URLWithString:urlString]];
      [request setHTTPMethod:@"POST"];
      NSMutableData *body = [NSMutableData data];
      NSString *boundary = @"---------------------------14737809831466499882746641449";
      NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
      [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
      
      [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
      [body appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"a.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      [body appendData:[NSData dataWithData:imgData]];
      [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
      //  parameter UserId
      
      [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
      [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userid\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
      
      [body appendData:[appDelegate.strUserID dataUsingEncoding:NSUTF8StringEncoding]];
      [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
      
      // close form
      [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
      
      
      // setting the body of the post to the request 
      [request setHTTPBody:body];
      
      
      NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
      // NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
      NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableLeaves error:nil];
      NSLog(@"%@",dict);
      

      【讨论】:

      • 非常感谢您的代码!其他的 sn-ps 没有用,和你的不同的是你用边界关闭了表单。
      【解决方案5】:

      我看到您在一个请求中发送了多个文件,对吗?

      HTTP specification,你应该使用 multipart/mixed Content-type inside embedding multipart/form-data

      以上链接示例:

      Content-type: multipart/form-data, boundary=AaB03x
      
      --AaB03x
      content-disposition: form-data; name="field1"
      
       Joe Blow
       --AaB03x
       content-disposition: form-data; name="pics"
       Content-type: multipart/mixed, boundary=BbC04y
      
       --BbC04y
        Content-disposition: attachment; filename="file1.txt"
      

      【讨论】:

      • 你知道如何从这里获取php中的每个数据
      猜你喜欢
      • 1970-01-01
      • 2012-06-20
      • 1970-01-01
      • 2017-06-07
      • 2012-02-09
      • 2012-01-23
      • 1970-01-01
      相关资源
      最近更新 更多