Nashorn环境下不落地磁盘将Base64文件以Multipart形式POST至URL
问题:Nashorn环境中multipart/form-data发送Base64解码文件失败
运行在Nashorn环境中,需将Base64编码的文件内容通过HTTP以multipart表单形式发送,现有代码在字节处理上存在问题:发送至httpbin.org时返回异常文件内容,发送至真实服务器时返回500错误,且环境中无ByteArrayBody类,只能使用基础Java API。
原代码
//获取Bearer Token的前置代码无问题 var boundary = java.util.UUID.randomUUID().toString(); var headers = { "Authorization": "Bearer "+ token, "Transfer-Encoding": "chunked", "Content-Type": "multipart/form-data; boundary=" + boundary }; var con = new java.net.URL("theUrl").openConnection(); con.requestMethod = "POST"; var hk = Object.keys(headers); for (var key of hk){ con.setRequestProperty(key, headers[key]); } // 发送POST请求 con.doOutput=true; var rn="\r\n"; var dos = new java.io.DataOutputStream(con.outputStream); var b64 = Java.type("java.util.Base64"); dos.writeBytes("--" + boundary + rn); dos.writeBytes("Content-Disposition: form-data; name=\"mycontent\"; filename=\"mycontent.zip\"" + rn); dos.writeBytes("Content-Type: application/octet-stream" + rn); dos.writeBytes("Content-Transfer-Encoding: binary" + rn); dos.writeBytes(rn); mydata = b64.getDecoder().decode(content_pack).toString().getBytes(); //此处可能存在问题 dos.write(mydata, 0, mydata.length); //或者此处有问题? dos.writeBytes(rn); dos.flush(); // 结束multipart/form-data dos.writeBytes("--" + boundary + "--" + rn); dos.flush(); dos.close(); asResponse(con); //读取响应并返回JSON对象
httpbin.org响应结果
{ "data": "{ \"args\": {}, \"data\": \"\", \"files\": { \"content-pack\": \"[B@5e3b67a5\" }, \"form\": {}, \"headers\": { \"Accept\": \"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\", \"Authorization\": \"Bearer Dab35ZB60lIdgI\", \"Content-Length\": \"254\", \"Content-Type\": \"multipart/form-data;boundary=b9aff414-4066-4e4b-9165-fc315ca4e02e\", \"Host\": \"httpbin.org\", \"User-Agent\": \"Java/11.0.20\", \"X-Amzn-Trace-Id\": \"Root=1-64e5cbc3-3feefbcc4bcb86c374402dc8\" }, \"json\": null, \"origin\": \"111.1.26.12\", \"url\": \"https://httpbin.org/post\"}", "headers": { "null": "HTTP/1.1 200 OK", "Server": "gunicorn/19.9.0", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true", "Connection": "keep-alive", "Content-Length": "587", "Date": "Wed, 23 Aug 2023 09:05:08 GMT", "Content-Type": "application/json" }, "statusCode": 200}
问题分析与修正
核心错误在于字节数组的错误转换:b64.getDecoder().decode(content_pack)已经得到原始文件的字节数组,调用toString()会将其转为[B@xxxx格式的字符串(这是Java字节数组的默认toString输出),再调用getBytes()得到的是这个字符串的字节,而非原始文件的字节,导致发送的文件内容完全错误。
修正后的代码
//获取Bearer Token的前置代码无问题 var boundary = java.util.UUID.randomUUID().toString(); var headers = { "Authorization": "Bearer "+ token, "Content-Type": "multipart/form-data; boundary=" + boundary }; var con = new java.net.URL("theUrl").openConnection(); con.requestMethod = "POST"; var hk = Object.keys(headers); for (var key of hk){ con.setRequestProperty(key, headers[key]); } // 发送POST请求 con.doOutput=true; var rn="\r\n"; var dos = new java.io.DataOutputStream(con.outputStream); var b64 = Java.type("java.util.Base64"); dos.writeBytes("--" + boundary + rn); dos.writeBytes("Content-Disposition: form-data; name=\"mycontent\"; filename=\"mycontent.zip\"" + rn); dos.writeBytes("Content-Type: application/octet-stream" + rn); dos.writeBytes(rn); // 移除Content-Transfer-Encoding,multipart默认支持二进制传输 // 直接使用解码后的原始字节数组 var mydata = b64.getDecoder().decode(content_pack); dos.write(mydata, 0, mydata.length); dos.writeBytes(rn); // 结束multipart/form-data dos.writeBytes("--" + boundary + "--" + rn); dos.flush(); dos.close(); asResponse(con); //读取响应并返回JSON对象
关键修正点
- 移除错误的字节转换:直接使用Base64解码后的字节数组,跳过
toString().getBytes()的无效转换 - 移除不必要的请求头:删除
Transfer-Encoding: chunked,Java的URLConnection会根据内容自动处理传输编码,手动设置可能引发冲突 - 简化Content-Transfer-Encoding:multipart/form-data默认支持二进制传输,可省略该头或保持为
binary - 确保格式完整性:保证multipart的边界、换行符格式完全符合HTTP规范
内容的提问来源于stack exchange,提问作者user2360915
相关产品推荐
相关产品推荐

