HTTURLConnection setFixedLengthStreamingMode 会导致 SSL 断开管道异常



我正在尝试从 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 = "rn";
    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();
        }
    }
}

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

最新更新