Ktor踩坑,上传文件同时带参的问题
2019-04-29 本文已影响33人
何晓杰Dev
之前写过一篇Ktor响应请求并接受参数的(点击查看),在该篇文章内讲述了一种上传文件的方法,使用 call.receiveMultipart()
来对上传的文件进行接收。
然而该案例仅有一个文件被上传,对部分同学造成了误导,有人给我提了这样一个问题:
post("/upload") {
val p = call.receiveParameters()
val part = call.receiveMultipart()
val desc = p["desc"] ?: ""
val file = part.readPart() as? PartData.FileItem
// save file...
}
用这样的代码来接受一个 post 请求,该请求的形式为:
var fd = new FormData();
fd.append('file', img);
fd.append('desc', desc);
$.ajax({
url: '/req',
type: 'POST',
dataType: 'json',
data: fd
});
“诶,看起来没错啊”,第一眼看到这代码时,我也觉得似乎是对的,但是实际跑一下,这份代码是会报错的,下面细细说来。
首先,对于一个 post 请求,是要分清楚 Content-Type
的,虽然在请求里没有明说,但是我们应当可以推断出不同的请求会拥有的不同Contentt-Type
。对于不带文件上传的请求,其 Content-Type
应当是 application/x-www-form-urlencoded
,而对于带文件的,是 multipart/form-data
,因此,对于带了文件又带了普通参数的请求,应当使用call.receiveMultipart()
来接收。
那么接下来的问题就容易了,无非是如何取数据的问题,下面给两个函数:
suspend fun MultiPartData.value(name: String) =
try { (readAllParts().filter { it.name == name }[0] as? PartData.FormItem)?.value } catch(e: Exception) { null }
suspend fun MultiPartData.file(name: String) =
try { readAllParts().filter { it.name == name }[0] as? PartData.FileItem } catch(e: Exception) { null }
然后在收到带文件上传的请求时,就可以这样做了:
post("/upload") {
val part = call.receiveMultipart()
val desc = part.value("desc") ?: ""
val file = part.file("file")
// save file...
}