如何在 VertX 中完成分段上传后关闭连接
How to close connection after Multipart Upload completes in VertX
我正在 VertX 中构建流式上传,以便我可以将上传直接流式传输到 Google Cloud / AWS S3 存储桶,但是当查看浏览器。
这是我使用的测试上传表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
<input type="text" value="blah">
<input multiple type="file">
</form>
<div>
</div>
<script>
let input = document.querySelector("input[type='file']")
let div = document.querySelector("div")
input.addEventListener("change", event => {
let files = event.target.files
console.log(files)
const formData = new FormData()
for (let file of files) {
formData.append(file.name, file)
formData.append("blah", "blah")
}
window.fetch("http://localhost:11111/le-upload-test?testing=true", {
method: "POST",
body: formData
}).then(response => {
div.innerHTML = ""
div.append(`${response.statusText} - ${response.status}`)
console.log(response)
})
})
</script>
</body>
</html>
在后端,
class MyServer(
val port: Int,
) : CoroutineVerticle() {
val log = LoggerFactory.getLogger(this.javaClass)
init {
Vertx.vertx()?.deployVerticle(this)
?: throw Exception("Failed to start VertX")
}
override suspend fun start() {
vertx.createHttpServer().requestHandler { req ->
println(req.path())
if (req.path() == "/le-upload-test") {
req.isExpectMultipart = true
req.uploadHandler { upload ->
println("==================")
println(req.params())
println(upload.filename())
println("==================")
upload.handler { chunk ->
println("chunk.length=${chunk.length()}")
println("total.read=${req.bytesRead()}")
}
}
}
}.listen(port)
}
}
fun main() {
MyServer(
port = 11111,
)
}
上传多个文件时,正确输出:
/le-upload-test
==================
testing=true
Screenshot_20201026_211340.png
==================
chunk.length=239
total.read=422
chunk.length=8192
total.read=8614
chunk.length=8192
...
==================
testing=true
Screenshot_20201026_181456.png
==================
chunk.length=192
total.read=74150
chunk.length=7770
total.read=81920
...
我应该在什么时候调用 req.response.end("...")
?
除非我重新启动服务器,否则浏览器会一直挂在那里?
我试过:
req.uploadHandler { upload ->
val contentLength = req.getHeader("Content-Length")
upload.handler { chunk ->
if (req.bytesRead().toString() == contentLength) {
println("DONE!!")
req.response().setStatusCode(200).end("DONE")
}
}
}
当所有字节都被处理后,这正确地打印了 DONE,但是浏览器随后显示失败,EMPTY RESPONSE
。
在upload.handler
之后添加一个upload.endHandler
upload.endHandler { end ->
println("DONE!!!")
req.response().setStatusCode(200).end("TEST")
}
在处理完所有字节后会正确打印 DONE!!!
部分,但也不会关闭状态为 200 的上传连接。
设法让它工作,似乎它只缺少一个 CORS header
override suspend fun start() {
vertx.createHttpServer().requestHandler { req ->
println(req.path())
try {
if (req.path() == "/le-upload-test") {
req.response().putHeader("Access-Control-Allow-Origin", "*")
req.isExpectMultipart = true
req.uploadHandler { upload ->
req.endHandler {
req.response().end("BLAH!!")
println("DONE")
}
我正在 VertX 中构建流式上传,以便我可以将上传直接流式传输到 Google Cloud / AWS S3 存储桶,但是当查看浏览器。
这是我使用的测试上传表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
<input type="text" value="blah">
<input multiple type="file">
</form>
<div>
</div>
<script>
let input = document.querySelector("input[type='file']")
let div = document.querySelector("div")
input.addEventListener("change", event => {
let files = event.target.files
console.log(files)
const formData = new FormData()
for (let file of files) {
formData.append(file.name, file)
formData.append("blah", "blah")
}
window.fetch("http://localhost:11111/le-upload-test?testing=true", {
method: "POST",
body: formData
}).then(response => {
div.innerHTML = ""
div.append(`${response.statusText} - ${response.status}`)
console.log(response)
})
})
</script>
</body>
</html>
在后端,
class MyServer(
val port: Int,
) : CoroutineVerticle() {
val log = LoggerFactory.getLogger(this.javaClass)
init {
Vertx.vertx()?.deployVerticle(this)
?: throw Exception("Failed to start VertX")
}
override suspend fun start() {
vertx.createHttpServer().requestHandler { req ->
println(req.path())
if (req.path() == "/le-upload-test") {
req.isExpectMultipart = true
req.uploadHandler { upload ->
println("==================")
println(req.params())
println(upload.filename())
println("==================")
upload.handler { chunk ->
println("chunk.length=${chunk.length()}")
println("total.read=${req.bytesRead()}")
}
}
}
}.listen(port)
}
}
fun main() {
MyServer(
port = 11111,
)
}
上传多个文件时,正确输出:
/le-upload-test
==================
testing=true
Screenshot_20201026_211340.png
==================
chunk.length=239
total.read=422
chunk.length=8192
total.read=8614
chunk.length=8192
...
==================
testing=true
Screenshot_20201026_181456.png
==================
chunk.length=192
total.read=74150
chunk.length=7770
total.read=81920
...
我应该在什么时候调用 req.response.end("...")
?
除非我重新启动服务器,否则浏览器会一直挂在那里?
我试过:
req.uploadHandler { upload ->
val contentLength = req.getHeader("Content-Length")
upload.handler { chunk ->
if (req.bytesRead().toString() == contentLength) {
println("DONE!!")
req.response().setStatusCode(200).end("DONE")
}
}
}
当所有字节都被处理后,这正确地打印了 DONE,但是浏览器随后显示失败,EMPTY RESPONSE
。
在upload.handler
upload.endHandler
upload.endHandler { end ->
println("DONE!!!")
req.response().setStatusCode(200).end("TEST")
}
在处理完所有字节后会正确打印 DONE!!!
部分,但也不会关闭状态为 200 的上传连接。
设法让它工作,似乎它只缺少一个 CORS header
override suspend fun start() {
vertx.createHttpServer().requestHandler { req ->
println(req.path())
try {
if (req.path() == "/le-upload-test") {
req.response().putHeader("Access-Control-Allow-Origin", "*")
req.isExpectMultipart = true
req.uploadHandler { upload ->
req.endHandler {
req.response().end("BLAH!!")
println("DONE")
}