在iOS上使用Method POST上载文件和文本

我试图发送一个JSON到一个文件和一些文本的Web服务,但服务器的答案是无效的。 我已经看了3天,不能得到什么错,所以我请求你的帮助。

这是与Web服务交谈的Web表单:

<html> <head> <title>Nova Dica Form</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form action="http://serveraddress.com/newtip" method="post" enctype="multipart/form-data"> <input type="hidden" name="textoDica" value="Ola teste dica"> <input type="hidden" name="idUsuario" value="2"> <input type="hidden" name="recomendou" value="true"> <input type="hidden" name="idTags" value="2"> <input type="hidden" name="idMarcas" value="1"> <input type="hidden" name="idLocais" value=""> <input type="hidden" name="idCategorias" value=""> <input type="hidden" name="idImpressoes" value=""> <input name="foto1" type="file"> <input name="foto2" type="file"> <input name="foto3" type="file"> <br> <input type="submit" value="Upload"> </form> </body> </html> 

这就是php开发者寄给我的东西:

 POST /newtip Host: serveraddress.com Content-Type: multipart/form-data Representation: Content-Disposition: form-data; name="textoDica" texto-dica Content-Disposition: form-data; name="foto1" Content-Type: image/jpeg, image/png Content-Transfer-Encoding: binary foto1 Content-Disposition: form-data; name="foto2" Content-Type: image/jpeg, image/png Content-Transfer-Encoding: binary foto2 Content-Disposition: form-data; name="foto3" Content-Type: image/jpeg, image/png Content-Transfer-Encoding: binary foto3 Content-Disposition: form-data; name="recomendou"; recomendou Content-Disposition: form-data; name="idUsuario"; id-usuario Content-Disposition: form-data; name="idTags"; id-tag Content-Disposition: form-data; name="idMarcas"; id-marca Content-Disposition: form-data; name="idLocais"; id-local Content-Disposition: form-data; name="idCategorias"; id-categoria Content-Disposition: form-data; name="idImpressoes"; id-Impressao Response Content-Type: application/json Representation: { "fotoDica" : "http://s3.amazonaws.com/cooltips/dicas/f23f89as.jpg", "horarioDica" : 1372711615696, "idDica" : 21, "recomendado" : 1, "textoDica" : "TesteDica1" } 

所以,基于这一点,我在我的代码(有一些内容,我在这里find了在计算器:

 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://serveraddress.com/newtip"]]]; [request setHTTPMethod:@"POST"]; // Header NSString *boundary = @"---------------------------14737809831466499882746641449"; NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; // Body NSMutableData *body = [NSMutableData data]; // Dica/Tip [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"textoDica\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Teste de texto blablabla." dataUsingEncoding:NSUTF8StringEncoding]]; // Usuario [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idUsuario\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"72" dataUsingEncoding:NSUTF8StringEncoding]]; // Recomendou [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"recomendou\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"true" dataUsingEncoding:NSUTF8StringEncoding]]; // Tags [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idTags\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"aaaaaa;bbbbbb;cccccc" dataUsingEncoding:NSUTF8StringEncoding]]; // Marca [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idMarcas\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"3" dataUsingEncoding:NSUTF8StringEncoding]]; // Local [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idLocais\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"4" dataUsingEncoding:NSUTF8StringEncoding]]; // Categorias [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idCategorias\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"1" dataUsingEncoding:NSUTF8StringEncoding]]; // Impressões [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"idImpressoes\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"bom;alegre" dataUsingEncoding:NSUTF8StringEncoding]]; // Fotos / Image Files [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"foto1\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Type: file/jpeg\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Transfer-Encoding: binary\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; NSData *imageData = UIImageJPEGRepresentation(_fotoArray[0], 0.40); [body appendData:[NSData dataWithData:imageData]]; // Final Boundary [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // Set the body [request setHTTPBody:body]; NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSLog(@"%@", returnString); 

我总是从服务器得到这个答案:

 {"idDica":0,"fotoDica":null,"horarioDica":null,"textoDica":null,"recomendado":0} 

但是正确的应该是这样的:

 {"idDica":91,"fotoDica":"http://serveraddress.com/tips/91/6nyIZA8MPJ.png","horarioDica":1372960438226,"textoDica":"Hello","recomendado":1} 

任何人都可以知道我做错了什么?

谢谢

编辑:这是networking服务代码(出于我的知识):

 @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) public DicaRest uploadFile( @FormDataParam("foto1") InputStream uploadedInputStream1, @FormDataParam("foto1") FormDataContentDisposition fileDetail1, @FormDataParam("foto2") InputStream uploadedInputStream2, @FormDataParam("foto2") FormDataContentDisposition fileDetail2, @FormDataParam("foto3") InputStream uploadedInputStream3, @FormDataParam("foto3") FormDataContentDisposition fileDetail3, @FormDataParam("textoDica") String textoDica, @FormDataParam("idUsuario") long idUsuario, @FormDataParam("recomendou") boolean recomendou, @FormDataParam("idTags") String idTags, @FormDataParam("idMarcas") String idMarcas, @FormDataParam("idLocais") String idLocais, @FormDataParam("idCategorias") String idCategorias, @FormDataParam("idImpressoes") String idImpressoes) { if(idTags == null) idTags = ""; if(idMarcas == null) idMarcas = ""; if(idLocais == null) idLocais = ""; if(idCategorias == null) idCategorias = ""; if(idImpressoes == null) idImpressoes = ""; EntityManager em = EntityFactory.getEntityManager("RestCTPU"); em.getTransaction().begin(); DicaRest dicaRest = new DicaRest(); Upload upload = new Upload(); List<File> pathfoto = new ArrayList<File>(); Dica novaDica = new Dica(); int i = 0; try { novaDica.setTextoDica(textoDica); novaDica.setIdUsuario(new Usuario(idUsuario)); novaDica.setRecomendado(recomendou); novaDica.setDataCadastro(new Date()); novaDica.setEstadoHabilitado(true); novaDica = em.merge(novaDica); //LINUX AMI String pathLocal = "/var/lib/tomcat7/webapps/uploadtemp/"+novaDica.getIdDica() + "/"; //WINDOWS //String pathLocal = "C:/teste/"+"dicas/"+novaDica.getIdDica() + "/"; String pathAlvo = "dicas/"+novaDica.getIdDica() + "/"; (new File(pathLocal)).mkdirs(); if (fileDetail1.getFileName().length() > 0) { pathfoto.add( new File(pathLocal+Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf(".")))); saveToFile(uploadedInputStream1, pathfoto.get(i).getAbsolutePath()); i++; } if (fileDetail2.getFileName().length() > 0) { pathfoto.add( new File(pathLocal +Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf(".")))); saveToFile(uploadedInputStream2, pathfoto.get(i).getAbsolutePath()); i++; } if (fileDetail3.getFileName().length() > 0) { pathfoto.add( new File(pathLocal+Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf(".")))); saveToFile(uploadedInputStream3, pathfoto.get(i).getAbsolutePath()); i++; } List<Tag> tags = new ArrayList<Tag>(); if(idTags.length() > 0) { String[] tgs = idTags.split(";"); for(String tag : tgs) { Tag nTag = new Tag(Long.valueOf(tag)); tags.add(nTag); } } novaDica.setTagList(tags); List<Alvo> alvos = new ArrayList<Alvo>(); if(idMarcas.length() > 0) { String[] marcas = idMarcas.split(";"); for(String marca : marcas) { Alvo nAlvo = new Alvo(Long.valueOf(marca)); alvos.add(nAlvo); } } if(idLocais.length() > 0) { String[] locais = idLocais.split(";"); for(String local : locais) { Alvo nAlvo = new Alvo(Long.valueOf(local)); alvos.add(nAlvo); } } novaDica.setAlvoList(alvos); List<CategoriaImpressao> categoriaImpressaoList = new ArrayList<CategoriaImpressao>(); if(idCategorias.length() > 0) { String[] categorias = idCategorias.split(";"); for(String categoria : categorias) { CategoriaImpressao nCat = new CategoriaImpressao(Long.valueOf(categoria)); categoriaImpressaoList.add(nCat); } } if(idImpressoes.length() > 0) { String[] impressoes = idImpressoes.split(";"); for(String impressao : impressoes) { CategoriaImpressao nImpress = new CategoriaImpressao(Long.valueOf(impressao)); categoriaImpressaoList.add(nImpress); } } novaDica.setCategoriaImpressaoList(categoriaImpressaoList); //String uploadedFileLocation = fileDetail1.getFileName(); // save it List<Foto> fts = new ArrayList<Foto>(); for(String foto : upload.doUpload(pathfoto, pathAlvo)) { Foto ft = new Foto(); ft.setUrlFoto(foto); ft.setIdDica(novaDica); ft.setDataCadastro(new Date()); ft.setEstadoHabilitado(true); fts.add(ft); } novaDica.setFotoList(fts); em.persist(novaDica); em.getTransaction().commit(); try { deleteDir(new File(pathLocal)); } catch (Exception e){} dicaRest.setFotoDica(fts.get(0).getUrlFoto()); dicaRest.setHorarioDica(new Date()); dicaRest.setIdDica(novaDica.getIdDica()); dicaRest.setRecomendado(recomendou); dicaRest.setTextoDica(textoDica); } catch (Exception e) { System.out.println(e); } finally { em.close(); em.getEntityManagerFactory().close(); } return dicaRest; } 

我会build议尝试指定上传文件名,例如:

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

你也可以使用Content-Typefile/jpeg ,但是开发者的spec说它应该是image/jpegimage/png 。 所以你可能想要使用:

 [body appendData:[@"Content-Type: image/jpeg\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 

如果这两者都没有这样做,我注意到你的值并不完全匹配HTML示例,并且由于我们不知道validation规则是什么,我build议你使用完全相同的值(例如idTags在HTML中是2 ,但在Objective-C中是aaaaaa;bbbbbb;cccccc )。 但是我们无法知道PHP正在执行什么validation,所以消除了只是不通过一些简单的validation规则的可能性。 确保您确信问题在于请求的形成,而不是您在请求中传递的数据。

希望你的PHP开发者能够精确地告诉你正在发生什么validation。


看看你的示例服务器源代码,我不太熟悉这个服务器代码来诊断它,但有一些想法:

  1. 看起来像引用,抓住fileDetail1扩展fileDetail2fileDetail3似乎不能正确(如果他们是不同的types?!?)。 鉴于你只通过一个,这不太可能是问题的根源,但这似乎不正确。

  2. 但是,这将表明,与我以前提供文件名的观察结果一致,这么做很重要,可能是一个带有jpg扩展名的文件。 我鼓励你包含一个文件名(即使它只是"test.jpg" )。

  3. 这段代码让我想知道当你的请求没有通过任何foto2foto3时会发生什么。 希望它能妥善处理,不要抛出任何exception,但我不能说。

  4. 我可能会误解这个,但看起来你的idTags必须用分号分隔,而不是aaaaaa;bbbbbb;cccccc 。 请参阅Long的参考。

  5. idImpressoes看起来也是这样,它应该用分号分开,而不是bom;alegre

这让我觉得,第4点和第5点是最直接的候选问题。 我会把这两个数字,看看是否修复它。