Как отключить буферизацию в Java HttpURLConnection для публикации формы из нескольких частей? - PullRequest
3 голосов
/ 11 июля 2011

(Это для подписанного апплета, и я решил не использовать HTTPClient, чтобы моя банка была очень маленькой)

Я использую HttpURLConnection для успешной загрузки файла от пользователя на сервер с помощью многочастной формы.

Проблема в том, что HttpURLConnection кэширует данные - перед отправкой. Поэтому, когда я читаю из файла и записываю в Outputstream, он просто буферизует данные - и поэтому мой индикатор выполнения, который показывает состояние загрузки, совершенно неверен. Однако, пожалуйста, обратите внимание, что почтовый индекс формы работает, и файл действительно загружен правильно с кодом возврата 200.

Итак, как мне убедиться, что HttpURLConnection не кэширует данные, которые я отправляю на сервер?

Вот мой источник:

public UploadResponse send(String formPostUrlStr,String fileFieldName,File targetFile, Map<String, String> valuesMap, UploadStatusListener uploadStatusListener) throws Exception{


    String sendStr=getBoundaryMessage(Boundary,  valuesMap, fileFieldName, targetFile.getName(), valuesMap.get("content-type") );//"image/png") ;

    System.out.println(" multi-part start \n "+ sendStr+ " multi-part end \n");

    String lenstr=Long.toString((long)(sendStr.length()*2)+ targetFile.length());
    System.out.println("Content-Length"+ lenstr);
                        //Content-Length

    URL url= new URL(formPostUrlStr);
    long startTime= System.currentTimeMillis();
    HttpURLConnection s3Connection = (HttpURLConnection) url.openConnection();

    System.out.println("opened url to "+ formPostUrlStr +", connection ok ..");
    s3Connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
            + Boundary);
    s3Connection.setRequestProperty("content-length",  lenstr);




    s3Connection.setDoOutput(true);
    s3Connection.setDoInput(true);
    s3Connection.setUseCaches(false);
     s3Connection.setInstanceFollowRedirects(true);
    s3Connection.setAllowUserInteraction(true);
    s3Connection.setRequestProperty("User-Agent", "Mozilla/4.5");


    if (uploadStatusListener != null) {
        uploadStatusListener.statusUpdate(targetFile.length(), 0);
    }


    String debugStr= s3Connection.toString();
    System.out.println("conmnection "+ debugStr);


    DataOutputStream httpOut = new DataOutputStream(s3Connection.getOutputStream());

    System.out.println("opened DataOutputStream ok ..");




    httpOut.write(sendStr.getBytes());


    //httpOut.flush();

  System.out.println("httpOut.flush 1 ok ..");
    FileInputStream uploadFileReader = new FileInputStream(targetFile);
    long totalBytes = uploadFileReader.available();
    if (uploadStatusListener != null) {
        uploadStatusListener.statusUpdate(totalBytes, 0);
    }
    System.out.println(" uploading file with size  "+ uploadFileReader.available());
    int bufSize = 102400;
    long availableBytesToRead;
    long totalSent = 0;
    while ((availableBytesToRead = uploadFileReader.available()) > 0) {
        byte[] bufferBytesRead;
        bufferBytesRead = availableBytesToRead >= bufSize ? new byte[bufSize]
                : new byte[(int)availableBytesToRead];
        int count = uploadFileReader.read(bufferBytesRead);
        try{
            httpOut.write(bufferBytesRead);
            totalSent += ((long) count);
            System.out.println(" wrote bytes = "+count+ ", total sent = "+ totalSent +", pendingSize"+ (availableBytesToRead-count) );
        }
        catch(IOException ioe){
            System.out.println(" io exceotion e"+ ioe.getMessage());
            throw ioe;
        }

        //httpOut.flush();
        if (uploadStatusListener != null) {
            uploadStatusListener.statusUpdate(totalBytes, totalSent);
        }

    }
    // FILE DATA END 
    httpOut.write(("--" + Boundary + "--\r\n").getBytes());



    // form end     
    httpOut.write(("--" + Boundary + "--\r\n").getBytes());

    httpOut.flush();
    httpOut.close();

    long endTime= System.currentTimeMillis();

    System.out.println("Completed Writing Data to S3 Connection in "+ (endTime-startTime)+"ms.,now waiting for rsponse code ");
    int code=s3Connection.getResponseCode();
    long endTime2= System.currentTimeMillis();
    System.out.println("Completed Sendind Data to S3 in "+ (endTime2-startTime)+ "ms., rsponse code time "+ (endTime2-endTime)+"ms. ");


    UploadResponse uploadResponse = new UploadResponse();

    uploadResponse.setCode(code);

    System.out.println(" response code : " + code);

    StringBuilder response = new StringBuilder();
    byte[] respBuffer = new byte[4096];


    if (code > 300) {
        if (code == 404) {
            throw new Exception("Error 404");
        }
        BufferedReader err = new BufferedReader(
                new InputStreamReader(s3Connection.getErrorStream()));
        String ret;
        StringBuffer buff = new StringBuffer();
        while ((ret = err.readLine()) != null) {
            buff.append(ret);
        }
        uploadResponse.setMessage(buff.toString());
        System.out.println(" error :"+ buff.toString());
        err.close();


    } else {
        BufferedReader inp = new BufferedReader(
                new InputStreamReader(s3Connection.getInputStream()));
        StringBuffer buff = new StringBuffer();
        String ret;
        while ((ret = inp.readLine()) != null) {
            buff.append(ret);
        }
        inp.close();
        uploadResponse.setMessage(buff.toString());
        if(buff.toString().contains("fail"))
            throw new Exception("Upload failed");
    }        

    System.out.println(response.toString());

    return uploadResponse;        

}

}

Ответы [ 2 ]

1 голос
/ 29 июля 2011

У меня такая же проблема. Я не нашел другого решения, кроме как написать свой HTTP-запрос на сыром сокете. Вы нашли лучший обходной путь?

РЕДАКТИРОВАТЬ: Я только что сделал: мы просто должны использовать obj.setFixedLengthStreamingMode (12345) для объекта HttpURLConnection, полученного из url.openConnection (), где 12345 - это длина тела запроса POST.

0 голосов
/ 09 августа 2018

В качестве дополнения к ответу, который дал @Antares, есть другой метод setChunkedStreamingMode, который используется, когда вы заранее не знаете размер контента.Поэтому, когда вы делаете запрос POST, вызывайте этот метод для соединения:

HttpURLConnection connection = ...
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
connection.connect();
... connection.getOutputStream();

Это позволит избежать, чтобы OutputStream буферизировал весь контент перед началом отправки.

...