且970 2024-11-23 17:24 采纳率: 0%
浏览 64
已结题

使用okhttp分片上传文件,总是超时,到底是哪里的问题

使用okhttp分片上传文件,总是超时,到底是哪里的问题,折腾还几天了。
在web端上传的地址,和我打印出来的地址都是一样的,上传第一个分片就超时。

web端的地址

img

Android打印的地址

img

api

img

  private static long CHUNK_SIZE = 26214400; // 每个分片的大小,25MB
private void UploadFile(String id, String name, long chunkSize, long size, Uri uri) {
        CHUNK_SIZE = chunkSize;
        OkHttpClient client = new OkHttpClient().newBuilder()
                .callTimeout(60000, TimeUnit.MILLISECONDS)
                .connectTimeout(60000, TimeUnit.MILLISECONDS)
                .readTimeout(60000, TimeUnit.MILLISECONDS).build();
        ContentResolver contentResolver = requireActivity().getContentResolver();
        try {
            InputStream inputStream = contentResolver.openInputStream(uri);
            if (inputStream == null) {
                throw new IOException("Failed to open input stream for URI: " + uri);
            }
            long fileSize = contentResolver.openFileDescriptor(uri, "r").getStatSize();
            long offset = 0;
            int chunkIndex = 0; // 分片编号从0开始
            while (offset < fileSize) {
                long chunk_Size = Math.min(CHUNK_SIZE, fileSize - offset);
                RequestBody requestBody = new ChunkedRequestBody(inputStream, offset, (int) chunk_Size);
                String uploadUrl = NasUrl.FILE_UPLOAD + "/" + id + "/" + chunkIndex; // 构建上传URL
                Log.e(TAG, "UploadFile: 分片大小:" + chunk_Size );
                Log.e(TAG, "UploadFile: 请求地址:" + uploadUrl );
                Request request = new Request.Builder()
                        .url(uploadUrl)
                        .method("POST",requestBody)
                        .header("Content-Length", String.valueOf(chunk_Size))
                        .header("Accept", "application/json, text/plain, */*")
                        .header("content-type", "aplication/octet-stream")
                        .build();

                try (Response response = client.newCall(request).execute()) {
                    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
                    Log.d("Upload", response.body().string());
                }
                offset += chunk_Size;
                chunkIndex++; // 准备上传下一个分片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class ChunkedRequestBody extends RequestBody {
        private final InputStream inputStream;
        private final long offset;
        private final int byteCount;

        ChunkedRequestBody(InputStream inputStream, long offset, int byteCount) {
            this.inputStream = inputStream;
            this.offset = offset;
            this.byteCount = byteCount;
        }

        @Override
        public MediaType contentType() {
            return MediaType.parse("application/octet-stream");
        }

        @Override
        public long contentLength() {
            return byteCount;
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            inputStream.skip(offset);
            byte[] buffer = new byte[8192];
            int bytesRead;
            long bytesRemaining = byteCount;
            while (bytesRemaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining))) != -1) {
                sink.write(buffer, 0, bytesRead);
                bytesRemaining -= bytesRead;
            }
        }
    }
  • 写回答

18条回答 默认 最新

  • 阿里嘎多学长 2024-11-23 17:24
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    使用okhttp分片上传文件总是超时的问题

    问题描述中,开发者使用OkHttp将大大小文件分片上传到服务器,但是总是超时,导致上传失败。

    问题分析:

    1. 问题可能来自于OkHttp的超时时间设置。OkHttp的三种超时时间:callTimeout、connectTimeout和readTimeout。实际情况中,这三个超时时间的设置可能影响上传的速度和成功率。
    2. 分片上传可能会出现网络传输延迟,导致超时。

    解决方案:

    1. 优化OkHttp的超时时间设置:
    OkHttpClient client = new OkHttpClient().newBuilder()
            .callTimeout(30000, TimeUnit.MILLISECONDS) // 调整callTimeout为30秒
            .connectTimeout(30000, TimeUnit.MILLISECONDS) // 调整connectTimeout为30秒
            .readTimeout(30000, TimeUnit.MILLISECONDS) // 调整readTimeout为30秒
            .build();
    
    1. 可以使用OkHttp的下载 managerspecies来处理网络连接超时,例如:
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url(uploadUrl)
            .method("POST",requestBody)
            .build();
    Response response = client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            
        }
    });
    
    1. 可以使用连接池来提高连接的可用性和加速网络传输速度。

    该方案可以解决OkHttp分片上传文件总是超时的问题,但是可能需要根据实际情况进行调整和fine-tuning。

    代码中设置的callTimeoutconnectTimeoutreadTimeout时间可以根据实际情况进行调整。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 11月23日
  • 修改了问题 11月23日
  • 创建了问题 11月23日