上传图片到服务器:初学者详细解释

8

我已经连续两天在上传图片到服务器方面进行了工作,因为有很多关于通过AFNetworking和NSURLSession以及其他上传方法的问题,所以我想问的是,我没有找到一个单一的答案来解释整个概念以及底层发生了什么事情。我还在YouTube上搜索过,但所有的内容都是使用Swift语言的,而且没有任何解释。最后,我发现这个答案与我之前看到的某些东西非常相似。


    //Init the NSURLSession with a configuration
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];

//Create an URLRequest
NSURL *url = [NSURL URLWithString:@"yourURL"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];

//Create POST Params and add it to HTTPBody
NSString *params = @"api_key=APIKEY&email=example@example.com&password=password";
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];

//Create task
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //Handle your response here
}];

[dataTask resume];

关于这个话题,最受欢迎的回答是由用户XJones给出的:


Here's code from my app to post an image to our web server:

// Dictionary that holds post parameters. You can set your post parameters that your server accepts or programmed to accept.
NSMutableDictionary* _params = [[NSMutableDictionary alloc] init];
[_params setObject:[NSString stringWithString:@"1.0"] forKey:[NSString stringWithString:@"ver"]];
[_params setObject:[NSString stringWithString:@"en"] forKey:[NSString stringWithString:@"lan"]];
[_params setObject:[NSString stringWithFormat:@"%d", userId] forKey:[NSString stringWithString:@"userId"]];
[_params setObject:[NSString stringWithFormat:@"%@",title] forKey:[NSString stringWithString:@"title"]];

// the boundary string : a random string, that will not repeat in post data, to separate post data fields.
NSString *BoundaryConstant = [NSString stringWithString:@"----------V2ymHFg03ehbqgZCaKO6jy"];

// string constant for the post parameter 'file'. My server uses this name: `file`. Your's may differ 
NSString* FileParamConstant = [NSString stringWithString:@"file"];

// the server url to which the image (or the media) is uploaded. Use your server url here
NSURL* requestURL = [NSURL URLWithString:@""]; 

// 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=%@", BoundaryConstant];
[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", BoundaryConstant] 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", BoundaryConstant] 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", BoundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]];

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

// set the content-length
NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];

// set URL
[request setURL:requestURL];

我的意思是,我自学时很难理解,因为没有解释,所以我想要一份详细的解释。如果有人发现这个问题很难,那么请给出一个关于整个过程的详细解释。直到现在,我找不到有关整个过程的教程,也没有任何面向初学者的解释。如果有人现在可以讲解一下这个概念以及上传过程,并提供一些参考步骤,那么明天要学习的学生就会更容易理解了。因此,任何可以详细解释上传过程并提供一些参考步骤的人都将受到高度赞赏。

注意:假设我有一个API和一个键“image”。

3个回答

4

在这里,我们将看一下图片上传以及一些**参数,因为大多数情况下,我们会同时上传一些参数,例如userId。

  • Before going deep into our topic let me provide the code for doing the stuff source,All the details we gonna see below are from some other stack overflow threads and some from other sites,i'll provide all the links for your reference.

    -(void)callApiWithParameters:(NSDictionary *)inputParameter images:(NSArray *)image  imageParamters:(NSArray *)FileParamConstant{
    
    //1
       NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    
       [request setHTTPShouldHandleCookies:NO];
       [request setTimeoutInterval:30];
       [request setHTTPMethod:@"POST"];
    
    //2
       NSString *boundary = @"------CLABoundaryGOKUL";
    
    //3
       NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
       [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    //4
       NSMutableData *body = [NSMutableData data];
    
       for (NSString *key in inputParameter) {
    
       [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
       [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
       [body appendData:[[NSString stringWithFormat:@"%@\r\n", [inputParameter objectForKey:key]] dataUsingEncoding:NSUTF8StringEncoding]];
      }
    
       for (int i = 0; i < image.count; i++) {
    
          NSData *imageDatasss = UIImagePNGRepresentation(image[i]);
    
          if (imageDatasss)
          {
              [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", FileParamConstant[i]] dataUsingEncoding:NSUTF8StringEncoding]];
              [body appendData:[@"Content-Type:image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
              [body appendData:imageDatasss];
              [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
         }
      }
    
      [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    //5
      [request setHTTPBody:body];
    
    //6
      [request setURL:[NSURL URLWithString:@"http://changeThisWithYourbaseURL?"]];//Eg:@"http://dev1.com/PTA_dev/webservice/webservice.php?"
    
    //7
      [NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    
                           NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    
                           //8
                           if ([httpResponse statusCode] == 200) {
                               NSDictionary * APIResult =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
                               NSLog(@"Response of %@: %@",[inputParameter valueForKey:@"service"],APIResult);
    
                           }else{
                               //9
                               NSLog(@"%@",error.localizedDescription);
                           }
                       }];
    
    
     }
    

    NOTE: Since it is a broad topic i have provided documentation link for detail info.

    1. We are using ** NSMutableURLRequest** instead of ** NSURLRequest** because we gonna append some data to it.if you need some deep clarification about mutable url request go through this documentation.
      • setHTTPShouldHandleCookies here we have to decide whether we are going to use cookies or not.To know more about visit
      • setTimeoutInterval this helps to set a time limit to url request.Add time interval in seconds after the given time,request will be terminated.
      • setHTTPMethod there are many methods.But we use GET and POST methods in many cases.Difference between POST and GET is here and here
    2. Boundary helps in separating the parameters from each other,so that the server can identify them.The boundary may be anything as your wish feel free to edit it.
    3. Here we use multipart/form-data; boundary= as content type.To know why we are going to this content type look into this thread.
    4. NSMutableData * body we gonna append all the parameters and values to this data and later setHTTPBody to the UrlRequest.

      • If this is how we call the 'callApiWithParameters' method

         - (IBAction)Done:(id)sender{
                NSDictionary * inputParameters = [NSDictionary dictionaryWithObjectsAndKeys:
                              @"1",@"user_id" ,
                              "XXX",@"name" ,
                              nil];
                 NSArray * image = [NSArray arrayWithObjects:[UIImage imageNamed:@"Test"],[UIImage imageNamed:@"Test1"],nil];
                 NSArray * imageParameters = [NSArray arrayWithObjects:@"img_one",@"img_two",nil];
                 [self callApiWithParameters:inputParameters images:image imageParamters:imageParameters];
          }
        
      • then the data (i.e body) will look like this

Content-Type=multipart/form-data; boundary=------CLABoundaryGOKUL

--------CLABoundaryGOKUL
Content-Disposition: form-data; name=user_id

1
--------CLABoundaryGOKUL
Content-Disposition: form-data; name=name

XXX
--------CLABoundaryGOKUL
Content-Disposition: form-data; name=img_one; filename=image.jpg

Content-Type:image/jpeg

//First image data appended here

--------CLABoundaryGOKUL
Content-Disposition: form-data; name=img_two; filename=image.jpg

Content-Type:image/jpeg

//Second image data appended here.
以下数据将清楚地解释正在发生的事情,所有参数和密钥都已附加在数据中。您可以在此处找到有关发送multipart/form的更多详细信息。
现在只需通过[request setHTTPBody:body];将上述数据添加到请求中。
在这个方法中setURL添加您应用程序的基本url。
现在我们需要做的就是连接服务器并发送请求。这里我们使用NSURLConnection发送请求。关于NSURLConnection的描述:为URL请求加载数据,并在请求完成或失败时在操作队列上执行处理程序块。 statusCode有助于确定我们是否从服务器获得了成功的响应。如果200表示OK,500表示内部服务器错误等。更多细节请参见此处
在else语句中处理错误。 FYI我已经尽力解释了,请参考链接以获得更好的理解。
编辑:只需更改imageParamater数组中的名称,为了满足您的要求,将img_one & img_two更改为image
 - (IBAction)Done:(id)sender{
     //Change input parameters as per your requirement.
     NSDictionary * inputParameters = [NSDictionary dictionaryWithObjectsAndKeys:
                                  @"1",@"user_id" ,
                                  "XXX",@"name" ,
                                  nil];
    NSArray * image = [NSArray arrayWithObjects:[UIImage imageNamed:@"Test"],nil]; //Change Test with your image name
    NSArray * imageParameters = [NSArray arrayWithObjects:@"image",nil];//Added image as a key.
    [self callApiWithParameters:inputParameters images:image imageParamters:imageParameters];
              }

请将例子基础URL填入到第六个变更点中。
//6
 [request setURL:[NSURL URLWithString:@"http://google.com/files/upload.php?"]];

太好了,这正是我在寻找的。感谢你的努力,兄弟。 - tryKuldeepTanwar
假设我有一个名为“Image”的密钥和一个API,例如“http://google.com/files/upload.php”,那么我需要在这个问题中进行哪些必要的更改才能得到响应?如果您根据我给出的要求上传不同的答案,那将非常有帮助,提前致谢。 - tryKuldeepTanwar
你需要将一张图片上传到API google.com/files/upload.php,并使用键值 image,对吗? - Gokul G
请检查已编辑的答案,它可能满足您的要求。 - Gokul G
让我们在聊天中继续这个讨论 - Gokul G

2

我认为这对你有帮助...

- (void)sendImageToServer
{
    UIImage *yourImage= [UIImage imageNamed:@"image.png"];
    NSData *imageData = UIImagePNGRepresentation(yourImage);
    NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    NSString *strImage = [NSString stringWithFormat:@"data:image/png;base64,%@",base64];

    NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithObjectsAndKeys:strImage,@"image", nil];
    NSError * err;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:0 error:&err];
    NSString *UserProfileInRequest = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSData *data=[UserProfileInRequest dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    NSString *len = [NSString stringWithFormat:@"%ld", (unsigned long)[data length]];

    // Init the URLRequest

    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
    [req setURL:[NSURL URLWithString:@"http://YOUR_URL"]];
    [req setHTTPMethod:@"POST"];
    [req setValue:len forHTTPHeaderField:@"Content-Type"];
    [req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [req setHTTPBody:data];

    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithRequest:req completionHandler:^(NSData *dt, NSURLResponse *response, NSError *err){
        //Response Data
        NSMutableDictionary *dic = [NSJSONSerialization JSONObjectWithData:dt options:kNilOptions error:&err];
        NSLog(@"%@", [dic description]);

    }]resume];
}

嘿@Ravi,感谢你的时间,但问题是我已经有很多解决方案了,但没有解释。我想知道整个过程,比如首先我们将图像转换为NSData,然后进行URL请求,然后进一步操作,这些额外字段都是用来做什么的,例如set-value、header等等。此外,NSURLConnection已被弃用,现在使用NSURLSession。 - tryKuldeepTanwar
好的,我明天会编辑我的答案,然后你可以检查一下我的答案。 - Ravi Dhorajiya
那将会很棒:) - tryKuldeepTanwar
你能逐行解释这个过程吗? - tryKuldeepTanwar
它也显示错误:Error Domain=NSCocoaErrorDomain Code=3840 "没有值。" UserInfo={NSDebugDescription=没有值。} - tryKuldeepTanwar

1
使用AFNetworking来完成此任务,这将提供非常简单可靠的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接