Java中用Multipart POST向Testrail测试运行传图片遇400错误求解
问题排查与修复方案
错误原因分析
- URL占位符未替换:请求URL中的
{result_id}是Testrail API的占位符,必须替换为真实的测试结果数字ID,直接使用占位符会导致API路径无效,返回400错误。 - 冗余HTTP连接初始化:代码中同时创建了
HttpURLConnection和HttpPost对象,但实际只用到了HttpPost,前者属于冗余代码,无实际作用。 - Base64编码字符集不明确:
(userName + ":" + userPassword).getBytes()默认使用系统字符集,可能导致认证信息编码错误,引发400。 - 过时的MultipartEntity:旧版本的
MultipartEntity已被标记为过时,部分环境下可能存在兼容性问题,导致请求格式不符合Testrail要求。
修改后的代码示例
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.Base64; public class TestrailAttachmentUpload { public static void main(String[] args) throws Exception { // 替换为真实的Testrail地址、测试结果ID、用户名、密码和文件路径 String testrailBaseUrl = ".../index.php?/api/v2/add_attachment_to_result/"; int actualResultId = 123; // 替换为真实的测试结果数字ID String userName = "your_testrail_username"; String userPassword = "your_testrail_password"; String screenshotPath = "path/to/your/failed_test_screenshot.jpg"; // 拼接完整请求URL String fullRequestUrl = testrailBaseUrl + actualResultId; // 创建标准HttpClient实例 HttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(fullRequestUrl); // 设置Basic认证头,指定UTF-8字符集避免编码问题 String authCredentials = userName + ":" + userPassword; byte[] encodedAuth = Base64.getEncoder().encode(authCredentials.getBytes(StandardCharsets.UTF_8)); String authHeader = "Basic " + new String(encodedAuth); httpPost.setHeader("Authorization", authHeader); // 使用MultipartEntityBuilder构建符合要求的多部分请求体 File screenshotFile = new File(screenshotPath); MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create(); entityBuilder.addBinaryBody( "userfile", screenshotFile, ContentType.IMAGE_JPEG, screenshotFile.getName() ); HttpEntity requestEntity = entityBuilder.build(); httpPost.setEntity(requestEntity); // 执行请求并输出响应 System.out.println("executing request " + httpPost.getRequestLine()); HttpResponse response = httpClient.execute(httpPost); HttpEntity responseEntity = response.getEntity(); System.out.println(response.getStatusLine()); if (responseEntity != null) { System.out.println(EntityUtils.toString(responseEntity)); } if (responseEntity != null) { responseEntity.consumeContent(); } } }
其他可行方法:使用OkHttp上传
如果不想依赖Apache HttpClient,可使用更简洁的OkHttp实现:
import okhttp3.*; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; public class TestrailOkHttpUpload { public static void main(String[] args) throws IOException { // 替换为真实参数 String fullRequestUrl = ".../index.php?/api/v2/add_attachment_to_result/123"; String userName = "your_testrail_username"; String userPassword = "your_testrail_password"; String screenshotPath = "path/to/your/failed_test_screenshot.jpg"; OkHttpClient client = new OkHttpClient(); File screenshotFile = new File(screenshotPath); // 构建多部分请求体 RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("userfile", screenshotFile.getName(), RequestBody.create(screenshotFile, MediaType.parse("image/jpeg"))) .build(); // 设置认证头 String authCredentials = userName + ":" + userPassword; String authHeader = "Basic " + Base64.getEncoder().encodeToString(authCredentials.getBytes(StandardCharsets.UTF_8)); // 构建并执行请求 Request request = new Request.Builder() .url(fullRequestUrl) .addHeader("Authorization", authHeader) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { System.out.println(response.code() + " " + response.message()); System.out.println(response.body().string()); } } }
额外检查项
- 确认
actualResultId是有效的测试结果ID,且属于已存在的测试运行。 - 确认截图文件路径正确,文件存在且程序有读取权限,文件大小不超过Testrail默认的10MB附件限制。
- 确认Testrail API已启用,且所用账号拥有对应测试结果的编辑权限。
内容的提问来源于stack exchange,提问作者NWL Test
相关产品推荐
相关产品推荐

