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!
Le processus est le suivant:
Créez un dictionnaire avec les paramètres userName
, userEmail
et userPassword
.
NSDictionary *params = @{@"userName" : @"rob",
@"userEmail" : @"[email protected]",
@"userPassword" : @"password"};
Déterminez le chemin de l'image:
NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];
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];
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;
}
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]];
}
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.");
}
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);
}
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];
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?
}
où 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"
}
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;