HttpUrlConnection多部分请求适配Multer报400错误排查
适配Multer的Multipart请求调整方案
我在应用中使用multipart request向服务器发送多文件及参数,此前适配express-formidable可正常运行,但切换为Multer后端库后功能失效。后端开发人员反馈接收的请求体为空,我收到400 - Bad Request响应。以下是需要调整的内容:
原请求代码
fun apiMultipart(): ApiResult { val url = URL(apiUrl) boundary = getBoundary() try { val connnection = createConnection(ApiMethod.POST.method, url) val requestStream = DataOutputStream(connnection.outputStream) formFieldData.data.forEach { ffd-> addFormField(ffd.first, ffd.second?:"null", requestStream) } addBitmapData(data, requestStream) addEnd(requestStream) requestStream.flush() return getResponse(connnection) }catch (e: IOException){ //return error - exception } } fun getResponse(con: HttpURLConnection): ApiResult{ //handle response } private const val LINE_FEED = "\r\n" private fun getBoundary(): String{ return "===" + System.currentTimeMillis() + "===" } private fun createConnection(method: String, url: URL): HttpURLConnection{ with(url.openConnection() as HttpURLConnection){ requestMethod = method setRequestProperty(HEADER_CONTENT_TYPE, "multipart/form-data;boundary=$boundary") addRequestProperty(HEADER_API_KEY, apiDef.apiKey) session?.let { addRequestProperty(HEADER_SESSION, it) } setRequestProperty("Accept", "*/*") setRequestProperty("Connection", "keep-alive") setRequestProperty("cache-control", "no-cache") doOutput = true return this } } /** * Adds a form field to the request * * @param name field name * @param value field value * @param outputStream data stream */ fun addFormField(name: String, value: Any, outputStream: DataOutputStream) { App.log("addFormFieldData: name: $name, value: $value") outputStream.apply { writeBytes("--$boundary$LINE_FEED") writeBytes("Content-Type: text/plain; charset=UTF-8;$LINE_FEED") writeBytes("Content-Disposition: form-data; name=\"$name\"$LINE_FEED$LINE_FEED") if (value is String){ write(value.toByteArray(StandardCharsets.UTF_8)) } else { writeBytes("$value") } writeBytes(LINE_FEED) } } fun addEnd(outputStream: DataOutputStream){ outputStream.apply { writeBytes(LINE_FEED) writeBytes("--$boundary$LINE_FEED") } } fun addFileEnd(outputStream: DataOutputStream){ outputStream.writeBytes(LINE_FEED) } fun addBitmapData(bmapsData: List<BitmapImageData>, outputStream: DataOutputStream){ bmapsData.forEach { bmData -> addFileHeader(bmData.name, bmData.name, "image/jpeg", outputStream) bmData.bm.compress(Bitmap.CompressFormat.JPEG, 60, outputStream) addFileEnd(outputStream) } } fun addFileHeader(name: String, filename: String, contentType: String, outputStream: DataOutputStream){ outputStream.apply { writeBytes("--$boundary$LINE_FEED") writeBytes("Content-Disposition: form-data; name=\"$name\"; filename=\"./$filename\"$LINE_FEED") writeBytes("Content-Type: $contentType$LINE_FEED$LINE_FEED") } }
具体调整点
修正请求结束边界格式:Multer要求multipart请求的结束边界必须是
--boundary--(前后各加两个短横线),原代码仅用了--boundary,导致请求未正确闭合。修改addEnd方法:fun addEnd(outputStream: DataOutputStream){ outputStream.apply { writeBytes("--$boundary--$LINE_FEED") // 末尾添加--完成闭合 } }同时移除原方法里多余的
LINE_FEED,避免出现无效空行。移除表单字段的冗余Content-Type头:普通表单字段不需要额外指定
text/plain头,Multer对冗余头的兼容性较差。修改addFormField方法,删除这一行:writeBytes("Content-Type: text/plain; charset=UTF-8;$LINE_FEED")修正文件名格式:原代码中文件名使用
./$filename的相对路径格式,Multer可能无法正确解析,直接使用文件名即可:// 修改addFileHeader中的这一行 writeBytes("Content-Disposition: form-data; name=\"$name\"; filename=\"$filename\"$LINE_FEED")规范换行符使用:确保所有字段、文件块之间的分隔严格使用
\r\n,避免出现多余空行。比如检查addFormField中写完字段值后的LINE_FEED,以及addFileEnd的换行是否必要,保证每个块的结构清晰。
调整原因
Multer对multipart请求的格式校验比express-formidable更严格,边界闭合格式、冗余头信息、文件名格式这些细节在formidable中可以兼容,但在Multer中会被判定为无效请求,直接返回400错误。调整后请求将符合Multer的解析要求。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

