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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 04:43:20