HttpClient и MultipartEntity против Джерси Multipart и Android - PullRequest
2 голосов
/ 03 ноября 2010

У меня есть веб-сервис отдыха, который принимает метод POST с составным сообщением:

@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..  

Теперь я пытаюсь написать Java-клиент для этого. Я начал с простого клиента из джерси: просмотреть обычную копию в буфер обмена?

    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);  

Это прекрасно работает - все в порядке. Однако мне нужен этот клиент, работающий на Android, и у меня проблемы с использованием джерси на этой платформе. Поэтому я использовал обычный способ отправки многочастного сообщения на 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);

Это дает раздражающий ответ от сервера:

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

Я проверяю файлы журнала сервера, но там ничего нет. Так что я не знаю, какова причина этой ошибки. Я написал простую HTML-страницу с формулой публикации и типом содержимого 'multipart / form-data', и это тоже работает! Автоматически сгенерированный запрос от soapUI также работает! Почему мой клиент не работает? Кто-нибудь может помочь?

1 Ответ

1 голос
/ 15 марта 2012

В Джерси есть ошибка. См. Проблема кодированного кода .

Эта проблема появляется только для нескольких клиентов (iOS, Android).

Если вы установите Content-Type на application / octet-stream, то Jersey MessageWriter для application / octet-stream установит Content-Length и не отправлять в виде фрагментированного транспорта.

Существует решение для Джерси. Клиент:

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

Но это не работает для клиента iOS или Android . Итак, я проверил Apache File Upload. Была еще одна ошибка: «Поток неожиданно закончился».

Только Загрузка Oreilly может загрузить файл правильно для всех клиентов. Это мой код:

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, 11024); // 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};
}
*1024* А это код сервера Джерси (предупреждающий, что все аннотации загрузки Джерси (например, как @FormDataParam) должны быть удалены):
@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);
    ...
}
...