web-dev-qa-db-fra.com

POST multipart/form-data avec Objective-C

Donc, ce code HTML soumet les données dans le format correct pour moi.

<form action="https://www.example.com/register.php" method="post" enctype="multipart/form-data">
    Name: <input type="text" name="userName"><BR />
    Email: <input type="text" name="userEmail"><BR />
    Password: <input type="text" name="userPassword"><BR />
    Avatar: <input type="file" name="avatar"><BR />
    <input type="submit">
</form>

J'ai examiné un bon nombre d'articles sur la façon de créer un multipart/formulaire-données POST sur iOS, mais aucun n'indique vraiment ce qu'il faut faire s'il y avait des paramètres normaux ainsi que le téléchargement de fichier.

Pourriez-vous s'il vous plaît m'aider avec le code pour POST ceci dans Obj-C?

Merci!

57
Ali Almohsen

Le processus est le suivant:

  1. Créez un dictionnaire avec les paramètres userName, userEmail et userPassword.

    NSDictionary *params = @{@"userName"     : @"rob",
                             @"userEmail"    : @"[email protected]",
                             @"userPassword" : @"password"};
    
  2. Déterminez le chemin de l'image:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];
    
  3. Créer la demande:

    NSString *boundary = [self generateBoundaryString];
    
    // configure the request
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    [request setHTTPMethod:@"POST"];
    
    // set content type
    
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // create body
    
    NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params paths:@[path] fieldName:fieldName];
    
  4. C'est la méthode utilisée ci-dessus pour construire le corps de la requête:

    - (NSData *)createBodyWithBoundary:(NSString *)boundary
                            parameters:(NSDictionary *)parameters
                                 paths:(NSArray *)paths
                             fieldName:(NSString *)fieldName {
        NSMutableData *httpBody = [NSMutableData data];
    
        // add params (all params are strings)
    
        [parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
            [httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
        }];
    
        // add image data
    
        for (NSString *path in paths) {
            NSString *filename  = [path lastPathComponent];
            NSData   *data      = [NSData dataWithContentsOfFile:path];
            NSString *mimetype  = [self mimeTypeForPath:path];
    
            [httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:data];
            [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        [httpBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
        return httpBody;
    }
    
  5. Ce qui précède utilise les méthodes d’utilité suivantes:

    @import MobileCoreServices;    // only needed in iOS
    
    - (NSString *)mimeTypeForPath:(NSString *)path {
        // get a mime type for an extension using MobileCoreServices.framework
    
        CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
        CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
        assert(UTI != NULL);
    
        NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));
        assert(mimetype != NULL);
    
        CFRelease(UTI);
    
        return mimetype;
    }
    
    - (NSString *)generateBoundaryString {
        return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
    }
    
  6. Puis soumettez la demande. Il y a beaucoup, beaucoup d'options ici.

    Par exemple, si vous utilisez NSURLSession, vous pouvez créer NSURLSessionUploadTask:

    NSURLSession *session = [NSURLSession sharedSession];  // use sharedSession or create your own
    
    NSURLSessionTask *task = [session uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"result = %@", result);
    }];
    [task resume];
    

    Ou vous pouvez créer une NSURLSessionDataTask:

    request.HTTPBody = httpBody;
    
    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"result = %@", result);
    }];
    [task resume];
    

    Ce qui précède suppose que le serveur ne fait que renvoyer une réponse textuelle. Il est préférable que le serveur renvoie JSON, auquel cas vous utiliseriez NSJSONSerialization plutôt que NSString, méthode initWithData.

    De même, j'utilise les rendus de bloc d'achèvement de NSURLSession ci-dessus, mais n'hésitez pas à utiliser les rendus plus riches basés sur des délégués. Mais cela semble aller au-delà de la portée de cette question, je vais donc vous laisser cela.

Mais j'espère que cela illustre l'idée.


Je m'en voudrais de ne pas souligner que, beaucoup plus facile que ce qui précède, vous pouvez utiliser AFNetworking , en répétant les étapes 1 et 2 ci-dessus, mais en appelant simplement:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON; if web service returns JSON, remove this line
NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    NSError *error;
    if (![formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"avatar" fileName:[path lastPathComponent] mimeType:@"image/png" error:&error]) {
        NSLog(@"error appending part: %@", error);
    }
}  progress:nil success:^(NSURLSessionTask *task, id responseObject) {
    NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionTask *task, NSError *error) {
    NSLog(@"error = %@", error);
}];

if (!task) {
    NSLog(@"Creation of task failed.");
}
164
Rob

POST plusieurs images en utilisant plusieurs parties ou des données de formulaire avec Objective-C

-(void)multipleimageandstring
{
    NSString *urlString=@"URL NAME";

    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"];

    // file
    float low_bound = 0;
    float high_bound =5000;
    float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);//image1
    int intRndValue = (int)(rndValue + 0.5);
   NSString *str_image1 = [@(intRndValue) stringValue];

    UIImage *chosenImage1=[UIImage imageNamed:@"Purchase_GUI_curves-12 copy.png"];

    NSData *imageData = UIImageJPEGRepresentation(chosenImage1, 90);
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"files\"; filename=\"%@.png\"\r\n",str_image1] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithData:imageData]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];





    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"name\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Nilesh" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"apipassword\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:app.password] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"adminId\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:app.adminId] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    // close form
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    // set request body
    [request setHTTPBody:body];

    //return and test
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

    NSLog(@"%@", returnString);

}
2
manish gaurav

Essayez de l’utiliser pour les données vidéo et image avec différents types de mime.

NSDictionary *param;

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

// 1. Create `AFHTTPRequestSerializer` which will create your request.
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
NSMutableURLRequest *request;

NSData *fileData;
if ([objDoc.url containsString:@".mp4"]) {
    manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"application/json"];
    [serializer setValue:@"video/mp4" forHTTPHeaderField:@"Content-Type"];
    manager.requestSerializer = serializer;
}

// 2. Create an `NSMutableURLRequest`.

NSLog(@"filename =%@",objDoc.url);
request= [serializer multipartFormRequestWithMethod:@"POST" URLString:strUrl parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

    if ([objDoc.url containsString:@".mp4"]) {
        [formData appendPartWithFileData:fileData
                                    name:@"File"
                                fileName:@"video.mp4"
                                mimeType:@"video/mp4"];

    }else{
        [formData appendPartWithFileData:fileData
                                    name:@"File"
                                fileName:@"image.jpeg"
                                mimeType:@"image/jpeg"];
    }

} error:nil];

// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.

self.objeDocument.isUploading = [NSNumber numberWithInt:1];

self.operation = [manager HTTPRequestOperationWithRequest:request
                                                  success:^(AFHTTPRequestOperation *operation, id responseObject) {

                                                      NSLog(@"Success %@", responseObject);
                                                  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                      UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error!" message:@"The document attached has failed to upload." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                                                      [alert show];
                                                      [self.operation cancel];
                                                      NSLog(@"Failure %@", error.description);
                                                  }];


// 4. Set the progress block of the operation.
[self.operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
                                         long long totalBytesWritten,
                                         long long totalBytesExpectedToWrite) {
    NSLog(@"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite);
    float progress = (float)totalBytesWritten/(float)totalBytesExpectedToWrite;


}];

// 5. Begin!
[self.operation start];
1
Arvind Patidar

Essaye ça:

Swift 5

private func buildMultipartDataRequest(_ request: NetworkRequest, baseURL: NetworkEndPoint) -> URLRequest? {
  var returnRequest: NSMutableURLRequest?

  if let data = request.multipartData,
    let mimeType = request.mimeType,
    let fileName = request.fileName {

    var requestPath = request.endPoint.value
    if let urlParameters = request.urlParameters {
      requestPath += urlParameters.requestString()
    }

    let completePath = String(format: "%@%@", baseURL.value, requestPath)

    if let cleanPath = completePath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed),
      let url = URL(string: cleanPath) {

      returnRequest = NSMutableURLRequest(url: url)
      returnRequest?.httpMethod = request.HTTPMethod.rawValue

      var allheaders: [String: String] = [ :]
      if let headers = request.headers {
        allheaders = headers
      }

      returnRequest?.allHTTPHeaderFields = allheaders

      let boundary = boundaryString()
      returnRequest?.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

      let encoding: UInt = String.Encoding.utf8.rawValue

      if let boundaryStartData = "--\(boundary)\r\n".data(using: String.Encoding(rawValue: encoding)),
        let fileNameData = "Content-Disposition:form-data; name=\"picture\"; filename=\"\(fileName)\"\r\n".data(using: String.Encoding(rawValue: encoding)),
        let contentTypeData = "Content-Type: \(mimeType)\r\n\r\n".data(using: String.Encoding(rawValue: encoding)),
        let endLineData = "\r\n".data(using: String.Encoding(rawValue: encoding)),
        let boundaryEndData = "--\(boundary)--\r\n".data(using: String.Encoding(rawValue: encoding)) {

        let body = NSMutableData()

        if let bodyParameters = request.bodyParameters as? [String: AnyObject] {
          bodyParameters.forEach { (pair) in
            if let key = "Content-Disposition: form-data; name=\"\(pair.key)\"\r\n\r\n".data(using: String.Encoding(rawValue: encoding)),
              let value = "\(pair.value)\r\n".data(using: String.Encoding(rawValue: encoding)) {
                body.append(boundaryStartData)
                body.append(key)
                body.append(value)
            }
          }
        }

        body.append(boundaryStartData)
        body.append(fileNameData)

        body.append(contentTypeData)
        body.append(data)
        body.append(endLineData)
        body.append(boundaryEndData)

        returnRequest?.httpBody = body as Data
      }
    }
  }

   return returnRequest as URLRequest?
 }

NetworkRequest - protocole simple contenant les informations sur la demande

protocol NetworkRequest: class {

  var HTTPMethod: NetworkRequestType { get }

  var endPoint: NetworkEndPoint { get }

  var urlParameters: [String: AnyObject]? { get }

  var bodyParameters: AnyObject? { get }

  var headers: [String: String]? { get }

  var multipartData: Data? { get }

  var mimeType: NetworkMimeType? { get }

  var fileName: String? { get }
}

NetworkEndPoint - EndPoint Value

struct NetworkEndPoint {

  let value: String
}

Piqûre à la frontière

private func boundaryString() -> String {
  return "Boundary-\(UUID().uuidString)"
}

NetworkRequestType:

enum NetworkRequestType: String {

  case UNKNOWN

  case POST
  case GET
  case PUT
  case DELETE
  case PATCH
  // ....
}

NetworkMimeType

enum NetworkMimeType: String {

  case html, htm, shtml = "text/html"
  case css = "text/css"
  case xml = "text/xml"
  case gif = "image/gif"
  case jpeg, jpg = "image/jpeg"
  case jScript = "application/javascript"
  case atom = "application/atom+xml"
  case rss = "application/rss+xml"
  case mml = "text/mathml"
  case txt = "text/plain"
  case jad = "text/vnd.Sun.j2me.app-descriptor"
  case wml = "text/vnd.wap.wml"
  case htc = "text/x-component"
  case png = "image/png"
  case tiff, tif = "image/tiff"
  case wbmp = "image/vnd.wap.wbmp"
  case ico = "image/x-icon"
  case jng = "image/x-jng"
  case bmp = "image/x-ms-bmp"
  case svg, svgz = "image/svg+xml"
  case webp = "image/webp"
  case woff = "application/font-woff"
  case jar, war, ear = "application/Java-archive"
  case json = "application/json"
  case hqx = "application/mac-binhex40"
  case doc = "application/msword"
  case pdf = "application/pdf"
  case postscript, eps, aiPostscript = "application/postscript"
  case rtf = "application/rtf"
  case m3u8 = "application/vnd.Apple.mpegurl"
  case xls = "application/vnd.ms-Excel"
  case eot = "application/vnd.ms-fontobject"
  case ppt = "application/vnd.ms-PowerPoint"
  case wmlc = "application/vnd.wap.wmlc"
  case kml = "application/vnd.google-earth.kml+xml"
  case kmz = "application/vnd.google-earth.kmz"
  case sevenZ = "application/x-7z-compressed"
  case cco = "application/x-cocoa"
  case jardiff = "application/x-Java-archive-diff"
  case jnlp = "application/x-Java-jnlp-file"
  case run = "application/x-makeself"
  case Perl, perlm = "application/x-Perl"
  case prc, pdb = "application/x-pilot"
  case rar = "application/x-rar-compressed"
  case rpm = "application/x-redhat-package-manager"
  case sea = "application/x-sea"
  case swf = "application/x-shockwave-flash"
  case sit = "application/x-stuffit"
  case tcl = "application/x-tcl"
  case der, pem, crt = "application/x-x509-ca-cert"
  case xpi = "application/x-xpinstall"
  case xhtml = "application/xhtml+xml"
  case xspf = "application/xspf+xml"
  case Zip = "application/Zip"
  case bin, exe, dll, deb, dmg, iso, img, msi, msp, msm = "application/octet-stream"
  case docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
  case xlsx = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  case pptx = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
  case mid, midi, kar = "audio/midi"
  case mp3 = "audio/mpeg"
  case ogg = "audio/ogg"
  case m4a = "audio/x-m4a"
  case realAudio = "audio/x-realaudio"
  case threegpp, threegp = "video/3gpp"
  case mpts = "video/mp2t"
  case mp4 = "video/mp4"
  case mpeg, mpg = "video/mpeg"
  case mov = "video/quicktime"
  case webm = "video/webm"
  case flv = "video/x-flv"
  case m4v = "video/x-m4v"
  case mng = "video/x-mng"
  case asx, asf = "video/x-ms-asf"
  case wmv = "video/x-ms-wmv"
  case avi = "video/x-msvideo"
}
0
gbk

J'ai eu du mal avec cela pendant un moment, si vous cherchez à télécharger plusieurs images ou tout autre type de fichier, vous pouvez faire ce qui suit en utilisant AFNetworking 3.0

NSDictionary *params = @{key        : value,
                            ..... etc
                         };

 NSString *urlString = @"http://..... your endpoint url";

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON;  

NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    for (int x = 0 ; x< contentArray.count; x++) {
        AttachmentsModel *model = contentArray[x];

        if(model.type == ImageAttachmentType){
            [formData appendPartWithFileData:model.data name:model.name fileName:model.fileName mimeType:model.mimeType];

        }else if(model.type == AudioAttachmentType){
            NSURL *urlVideoFile = [NSURL fileURLWithPath:model.path];
            [formData appendPartWithFileURL:urlVideoFile name:model.name fileName:model.fileName mimeType:model.mimeType error:nil];
        }else{
            [formData appendPartWithFileURL:model.url name:model.name fileName:model.fileName mimeType:model.mimeType error:nil];

        }

    }
}  progress:nil success:^(NSURLSessionTask *task, id responseObject) {
    [Utility stopLoading];

     NSString *result = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    NSLog(@"result = %@", result);

    id json = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];


    if (block) {

        //your response comes here
    }

} failure:^(NSURLSessionTask *task, NSError *error) {
    NSLog(@"error = %@", error);

}];

if (!task) {
    NSLog(@"Creation of task failed.");
}

Et voici à quoi ressemble mon AttachmentsModel:

//  AttachmentsModel.h

typedef enum AttachmnetType{
    ImageAttachmentType,
    AudioAttachmentType,
    VideoAttachmentType
} AttachmnetType;

@interface AttachmentsModel : NSObject

@property (strong, nonatomic) NSString *path;
@property (strong, nonatomic) NSData *data;
@property (strong, nonatomic) NSString *mimeType;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *fileName;
@property (strong, nonatomic) NSURL *url;
0
Mutawe