You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将含multipart文件上传的curl转为原生Groovy请求报415如何解决

问题根因
  • 415状态码由错误的请求Content-Type导致:你当前代码设置的是application/json,但curl中-F参数对应的是multipart/form-data类型的多部件表单提交
  • 缺失多部件表单的文件上传逻辑,两个JSON文件未按表单格式写入请求体
原生Groovy实现代码(无第三方依赖)
String strBaseURL = 'https://jstg.XXXXXXX.com/'
String strUserName = 'myuser'
//TODO set password before testing
String strUserPwd = 'fakepassword'
String strInfoFile = 'C:\\temp\\JSON\\executionInfo_Pretty.json'
String strExecResultsFile = 'C:\\temp\\JSON\\execResults_pretty.json'
String strAPIPath = 'rest/raven/1.0/import/execution/multipart'
String strAuthType = 'Basic'

// 生成multipart边界标识
String boundary = "----WebKitFormBoundary${new Random().nextInt(999999999)}"
String lineBreak = '\r\n'

String authString = "${strUserName}:${strUserPwd}".getBytes().encodeBase64().toString()
URL url = new URL("${strBaseURL}${strAPIPath}")
HttpURLConnection conXray = (HttpURLConnection) url.openConnection()
conXray.with {
    requestMethod = 'POST'
    connectTimeout = 10000
    readTimeout = 30000
    doOutput = true
    doInput = true
    // 修正Content-Type为multipart表单类型
    setRequestProperty('Authorization', "${strAuthType} ${authString}")
    setRequestProperty('Content-Type', "multipart/form-data; boundary=${boundary}")
}

// 写入请求体
conXray.outputStream.with { out ->
    // 写入第一个文件:info字段
    out.write("--${boundary}${lineBreak}".bytes)
    out.write("Content-Disposition: form-data; name=\"info\"; filename=\"${new File(strInfoFile).name}\"${lineBreak}".bytes)
    out.write("Content-Type: application/json${lineBreak}${lineBreak}".bytes)
    out.write(new File(strInfoFile).bytes)
    out.write(lineBreak.bytes)

    // 写入第二个文件:result字段
    out.write("--${boundary}${lineBreak}".bytes)
    out.write("Content-Disposition: form-data; name=\"result\"; filename=\"${new File(strExecResultsFile).name}\"${lineBreak}".bytes)
    out.write("Content-Type: application/json${lineBreak}${lineBreak}".bytes)
    out.write(new File(strExecResultsFile).bytes)
    out.write(lineBreak.bytes)

    // 写入multipart结束标记
    out.write("--${boundary}--${lineBreak}".bytes)
    out.flush()
}

// 读取响应结果
def responseCode = conXray.responseCode
def responseText
if (responseCode >= 200 && responseCode < 300) {
    responseText = conXray.inputStream.getText('UTF-8')
} else {
    responseText = conXray.errorStream?.getText('UTF-8') ?: '无错误信息'
}
conXray.disconnect()

// 输出结果
println "响应状态码:${responseCode}"
println "响应内容:${responseText}"
关键说明
  • 边界字符串boundary用来分隔表单中的不同字段,值可以自定义,只要和请求体内容不冲突即可
  • 两个表单字段名info和result和curl命令中的-F参数的键完全对应,不能写错
  • Groovy自带的with、withStream语法糖会自动关闭流,无需手动处理资源释放

内容的提问来源于stack exchange,提问作者PGK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 01:21:03