1

我正在尝试从 Egnyte 将文件上传到 REST API如果我不使用 setFixedLengthStreamingMode(...) 上传文件时不会出现异常,当我使用 setFixedLengthStreamingMode(...) 时,我会在 IO/ SSL 异常 -> 管道损坏。

为什么我需要这个?正如 HTTURLConnection 的文档所表明的那样,如果您不设置内容长度或使用 setChunkedStreamingMode() 那么整个文件将在发送之前缓存在客户端的内存中,这是不好的,因为如果文件太大我可以得到OOM 异常。您是否看到我的代码中缺少某些内容?

private Integer doFileUpload(final String urlServer, final String pathToOurFile) {
    HttpURLConnection connection = null;
    DataOutputStream outputStream = null;
    FileInputStream fileInputStream = null;

    String lineEnd = "\r\n";
    String twoHyphens = "--";
    String boundary = "*****";

    int bytesRead, fileLength, bufferSize;
    final int fileSize;
    byte[] buffer;
    int maxBufferSize = 1 * 1024 * 1024;

    try {
        File file = new File(pathToOurFile);
        fileInputStream = new FileInputStream(file);

        URL url = new URL(urlServer);
        connection = (HttpURLConnection) url.openConnection();

        String[] payload = { twoHyphens + boundary + lineEnd,
                "Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile + "\"" + lineEnd, lineEnd, lineEnd,
                twoHyphens + boundary + twoHyphens + lineEnd };

        int payloadLength = 0;
        for (String string : payload) {
            payloadLength += string.getBytes("UTF-8").length;
        }
        Logger.d(TAG, "payload length: " + payloadLength);
        fileLength = fileInputStream.available();
        Logger.d(TAG, "bytes: " + fileLength);

        // Not working:
        //            connection.setFixedLengthStreamingMode(fileLength + payloadLength);

        fileSize = fileLength;

        // Allow Inputs & Outputs
        connection.setDoInput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);

        connection.setReadTimeout(5000);
        connection.setConnectTimeout(5000);

        connection.setRequestProperty("Authorization", "Bearer " + mToken);

        // Enable POST method
        connection.setRequestMethod(HttpPost.METHOD_NAME);

        //            connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Connection", "close");

        // This header doesn't count to the number of bytes being sent.
        connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        //            String mimeType = Utils.getMimeType(file.getName());
        //            connection.setRequestProperty("Content-Type", mimeType);

        connection.connect();
        outputStream = new DataOutputStream(connection.getOutputStream());

        outputStream.writeBytes(payload[0]);
        outputStream.writeBytes(payload[1]);
        outputStream.writeBytes(payload[2]);

        bufferSize = Math.min(fileLength, maxBufferSize);
        buffer = new byte[bufferSize];

        // Read file
        bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        final int updateIntervalMilliseconds = 500; // update the UI 2 times a second
        boolean stopUploading = (FileState.UPLOADING != mFileInfo.getState() || isCancelled());
        long totalBytesRead = 0;
        long lastProgressTime = 0;

        while (bytesRead > 0 && !stopUploading)
        {
            Logger.d(TAG, "bytes read: " + totalBytesRead);
            stopUploading = (FileState.UPLOADING != mFileInfo.getState() || isCancelled());
            if (!stopUploading) {
                totalBytesRead += bytesRead;

                outputStream.write(buffer, 0, bufferSize);
                fileLength = fileInputStream.available();
                bufferSize = Math.min(fileLength, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                // send a progress update event in regular intervals
                long now = System.currentTimeMillis();
                if (now - lastProgressTime > updateIntervalMilliseconds) {
                    lastProgressTime = now;
                    final int percentCompleted = (int) ((totalBytesRead * 100) / fileSize);
                    if (!stopUploading && mFileInfo.getProgress() != percentCompleted) {
                        mFileInfo.sendEvent(FileEvent.UPLOAD_PROGRESS, percentCompleted);
                    }
                }
            }
        }

        outputStream.writeBytes(payload[3]);
        outputStream.writeBytes(payload[4]);

        // Responses from the server (code and message)
        int serverResponseCode = connection.getResponseCode();

        if (serverResponseCode == HttpStatus.SC_OK || serverResponseCode == HttpStatus.SC_CREATED) {
            return JBError.JBERR_SUCCESS;
        } else {
            return serverResponseCode;
        }

    } catch (SocketTimeoutException e) {
        //applayExponentialBackoff(n);
        Log.e(TAG, "SocketTimeoutException");
        return JBError.JBERR_NO_NETWORK;
    } catch (UnknownHostException e) {
        Log.e(TAG, "UnknownHostException");
        return JBError.JBERR_NO_NETWORK;
    } catch (SocketException e) {
        Log.e(TAG, "SocketException");
        return JBError.JBERR_NO_NETWORK;
    } catch (IOException e) {
        Log.e(TAG, "IOException");
        e.printStackTrace();
        return JBError.JBERR_FAILED;
    } catch (Exception ex) {
        Log.e(TAG, "Exception");
        ex.printStackTrace();
        return JBError.JBERR_FAILED;
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
        try {
            if (fileInputStream != null) {
                fileInputStream.close();
            }
            if (outputStream != null) {
                outputStream.flush();
                outputStream.close();
            }

        } catch (IOException e) {
            Log.e(TAG, "IOException");
            e.printStackTrace();
        }
    }
}
4

1 回答 1

1

内容长度计算正确?如果您不确定,请尝试改用固定长度使用分块模式。对于 android,它类似于 setChunkedStreamingMode(int chunkLength)。

于 2013-12-12T15:53:14.327 回答