2010-11-03 8 views
2

J'ai un webservice de repos qui prend un metod POST avec un message multipart:HttpClient et MultipartEntity contre Jersey et Android multipart

@Path("transferFile")  
@POST 
@Consumes(MediaType.MULTIPART_FORM_DATA) 
@Produces(MediaType.APPLICATION_XML) 
public String multipartTest(com.sun.jersey.multipart.MultiPart data) { 
try { 
// get first body part (index 0)   
BodyPart bp = multiPart.getBodyParts().get(0); 
etc.. 

Maintenant, je suis en train d'écrire un client java pour cela. J'ai commencé avec un simple client maillot: voir plaincopy à clipboardprint?

MultiPart multiPart = new MultiPart(); 
    multiPart.bodyPart(new BodyPart(wavestream,MediaType.APPLICATION_OCTET_STREAM_TYPE)); 

    Client c = Client.create(); 
    WebResource r = c.resource("http://127.0.0.1:8080/webapp:); 
response=r.path("transferFile").type(MediaType.MULTIPART_FORM_DATA).accept(MediaType.APPLICATION_XML).post(String.class, multiPart); 

Cela fonctionne très bien - tout est ok. Cependant, j'ai besoin que ce client travaille sur Android et j'ai du mal à utiliser le maillot sur cette plate-forme. Alors je la voie normale d'envoyer un message multipart sur android:

HttpClient client = new DefaultHttpClient(); 
client.getParams().setParameter("http.socket.timeout", new Integer(90000)); // 90 second 

HttpPost httpPost = new HttpPost("http://127.0.0.1:8080/webapp/transferFile"); 
httpPost.setHeader("Content-Type", MediaType.MULTIPART_FORM_DATA); 

//tried with and without base64 
byte [] encodedWavestream = Base64.encodeBytesToBytes(wavestream); 
InputStream ins = new ByteArrayInputStream(encodedWavestream); 
InputStreamBody body = new InputStreamBody(ins, "test"); 
int send = ins.available(); 

MultipartEntity requestContent = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); 
requestContent.addPart("stream", body); 

httpPost.setEntity(requestContent); 
HttpResponse Response = client.execute(httpPost); 

Un cela donne une réponse gênant du serveur:

HTTP Status 400 - Bad Request 
The request sent by the client was syntactically incorrect (Bad Request). 

Je vérifie les fichiers journaux de serveur, mais il n'y a rien là. Donc je ne sais pas quelle est l'origine de cette erreur. J'ai écrit une simple page html avec une formule post et un type de contenu 'multipart/form-data' et ça marche aussi! Une demande générée automatiquement par soapUI fonctionne également! Pourquoi mon client ne travaille pas? Quelqu'un peut-il aider?

+0

Je suppose que vous utilisez Android Emulateur et serveur d'applications sur le même hôte. Dans ce cas, vous devez utiliser 10.0.2.2 au lieu de localhost ou 127.0.0.1 pour atteindre le système hôte! Sinon, vous pointez sur le périphérique virtuel (émulé) lui-même. – Lars

Répondre

1

Il y a un bug dans Jersey. Voir Chunked encoding problem.

Ce problème n'apparaît que pour quelques clients (iOS, Android).

Si vous définissez le type de contenu sur application/octet-stream, le message Jersey MessageWriter du flux application/octet définit la longueur de contenu et ne l'envoie pas en tant que méthode de transport en blocs.

Il est solution pour Jersey Client:

ClientConfig config = new DefaultClientConfig(); 
config.getProperties().put(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 32 * 1024); 

Mais il ne fonctionne pas pour les iOS ou du client de Android. J'ai donc testé Apache File Upload. Threre était un autre bug: "Stream s'est terminé de façon inattendue".

Seul Oreilly upload peut télécharger le fichier correct pour tous les clients. Voici mon code:

public Object[] getParametersAndFiles(HttpServletRequest request) throws IOException { 
    log.debug("OreillyUpload"); 
    Properties params = new Properties(); 
    LinkedHashMap files = new LinkedHashMap(); 

    File tempDirectory = new File(System.getProperty("java.io.tmpdir")); 

    MultipartParser mp = new MultipartParser(request, 1*1024*1024); // 10MB 
    Part part; 
    while ((part = mp.readNextPart()) != null) { 
     String name = part.getName(); 
     if (part.isParam()) { 
      // it's a parameter part 
      ParamPart paramPart = (ParamPart) part; 
      String value = paramPart.getStringValue(); 
      params.put(name, value); 

      log.debug("param; name=" + name + ", value=" + value); 
     } 
     else if (part.isFile()) { 
      // it's a file part 
      FilePart filePart = (FilePart) part; 
      String fileName = filePart.getFileName(); 
      if (fileName != null) { 
       // the part actually contained a file 
       File file = new File(tempDirectory,fileName); 
       long size = filePart.writeTo(file); 
       files.put(name, file); 

       log.debug("file; name=" + name + "; filename=" + fileName + 
         ", filePath=" + filePart.getFilePath() + 
         ", content type=" + filePart.getContentType() + 
         ", size=" + size); 

      } 
      else { 
       // the field did not contain a file 
       log.debug("file; name=" + name + "; EMPTY"); 
      } 
     } 
    } 

    return new Object[] {params, files}; 
} 

Et c'est Jersey code serveur (avertissement tous anotations Jersey Télécharger (comme comme "@FormDataParam") doivent être supprimés):

@POST 
@Path("uploadMarkup") 
@Produces(MediaType.APPLICATION_JSON) 
// @Consumes(MediaType.MULTIPART_FORM_DATA) 
//// public void uploadMarkup(
// public JSONWithPadding uploadMarkup(
//   @FormDataParam("markupFile") InputStream markupFile, 
//   @FormDataParam("markupFile") FormDataContentDisposition details, 
//   @FormDataParam("slideNum") int slideNum) { 
public JSONWithPadding uploadMarkup(@Context HttpServletRequest request) { 
    Object[] data = uploadService.getParametersAndFiles(request); 
    ... 
}