问题
In my project, I should download a file chunk by chunk from one server and upload each chunk immediately to another server.
I have a URL of the file from where I should download. Let's call it downloadUrl
.
So, this is how I download file chunk by chunk:
val chunkSize = 1024 * 1024
BufferedInputStream(downloadUrl.openStream()).use { bis ->
val buffer = ByteArray(chunkSize)
var countBytesRead: Int
while (bis.read(buffer, 0, chunkSize).also { countBytesRead = it } != -1) {
// I should send buffer to another server
}
}
Now, I should send each chunk to another server. Code I do:
val chunkSize = 1024 * 1024
BufferedInputStream(downloadUrl.openStream()).use { bis ->
val buffer = ByteArray(chunkSize)
var countBytesRead: Int
val boundary = System.currentTimeMillis().toString(16)
val chunks = fileContentLength / chunkSize + if (contentLength % chunkSize != 0L) 1 else 0
while (bis.read(buffer, 0, chunkSize).also { countBytesRead = it } != -1) {
uploadChunkOfFile(
boundary = boundary,
chunk = buffer,
fileFullName = fileFullName,
chunkId = chunkId,
chunks = chunks.toInt()
)
chunkId++
}
}
fun uploadChunkOfFile(boundary: String, chunk: ByteArray, fileFullName: String, chunkId: Int, chunks: Int): String {
val url = "some_upload_url"
val connection = url.openConnection() as HttpURLConnection
val lineEnd = "\r\n"
val twoHyphens = "--"
val charset = "UTF-8"
connection.readTimeout = 20000
connection.connectTimeout = 20000
connection.doInput = true
connection.doOutput = true
connection.useCaches = false
connection.requestMethod = "POST"
connection.setRequestProperty("Connection", "Keep-Alive")
connection.addRequestProperty("token", "some_token")
connection.addRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")
val dos = DataOutputStream(connection.outputStream)
dos.writeBytes("$boundary$lineEnd")
// Send parameter #chunkId
dos.writeBytes("Content-Disposition: form-data; name=\"chunk\"$lineEnd")
dos.writeBytes("Content-Type: text/plain; charset=$charset$lineEnd")
dos.writeBytes("Content-Length: " + chunkId.toString().length + lineEnd)
dos.writeBytes(lineEnd)
dos.writeBytes(chunkId.toString() + lineEnd)
dos.writeBytes(twoHyphens + boundary + lineEnd)
// Send parameter #chunks
dos.writeBytes("Content-Disposition: form-data; name=\"chunks\"$lineEnd")
dos.writeBytes("Content-Type: text/plain; charset=$charset$lineEnd")
dos.writeBytes("Content-Length: " + chunks.toString().length + lineEnd)
dos.writeBytes(lineEnd)
dos.writeBytes(chunks.toString() + lineEnd)
dos.writeBytes(twoHyphens + boundary + lineEnd)
// Send parameter #name
dos.writeBytes("Content-Disposition: form-data; name=\"name\"$lineEnd")
dos.writeBytes("Content-Type: text/plain; charset=$charset$lineEnd")
dos.writeBytes("Content-Length: " + fileFullName.length + lineEnd)
dos.writeBytes(lineEnd)
dos.writeBytes(fileFullName + lineEnd)
dos.writeBytes(twoHyphens + boundary + lineEnd)
// Send parameter #file
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"$fileFullName\"$lineEnd") // filename is the Name of the File to be uploaded
dos.writeBytes("Content-Type: video/mp4$lineEnd")
dos.writeBytes(lineEnd)
dos.write(chunk)
dos.writeBytes(lineEnd)
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd)
println(dos)
dos.flush()
dos.close()
val responseCode = connection.responseCode
val responseMessage = connection.responseMessage
val br = if (responseCode in 200..299)
BufferedReader(InputStreamReader(connection.inputStream))
else BufferedReader(InputStreamReader(connection.errorStream))
println("chunkId: $chunkId, chunks: $chunks") // I print each chunk id
val sb = StringBuilder()
var output: String?
while (true) {
output = br.readLine()
if (output.isNullOrEmpty()) break;
sb.append(output)
}
println(sb.toString()) // I print response body of request
return sb.toString()
}
For each chunk, I get response code 200, except for the first chunk.
Log:
chunkId: 0, chunks: 17
responseCode: 500
responseMessage: Internal Server Error
<html><body><h1>Whitelabel Error Page</h1><p>This application has no configured error view, so you are seeing this as a fallback.</p><div id='created'>Fri Dec 27 12:54:43 UTC 2019</div><div>There was an unexpected error (type=Internal Server Error, status=500).</div><div>500 Internal Server Error</div></body></html>
chunkId: 1, chunks: 17
responseCode: 200
responseMessage: OK
{"uploadedFiles":[{"fileId":"0deb7af7-28a8-11ea-be77-ae88efe3f04a","fileName":"3c20c268-c19a-4b13-9135-1698f2f4da11.mp4"}]}
chunkId: 2, chunks: 17
responseCode: 200
responseMessage: OK
{"uploadedFiles":[{"fileId":"0e2319fe-28a8-11ea-ab01-aa6ef33510d7","fileName":"3c20c268-c19a-4b13-9135-1698f2f4da11.mp4"}]}
chunkId: 3, chunks: 17
...
来源:https://stackoverflow.com/questions/59501141/why-i-can-not-upload-first-chunk-of-file-by-using-httpurlconnection