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

Java Runtime.exec执行curl报415错误 终端同命令执行正常解决方案

问题根因

415错误的核心原因是Runtime.getRuntime().exec(String)的命令解析逻辑和终端shell完全不同:

  • 终端执行curl命令时,shell会先做语法解析,自动剥离参数外层的双引号,最终把Content-Type: application/json作为完整的Header值传给curl进程,所以调用正常。
  • 直接把完整命令字符串传给exec()方法时,Java不会调用系统shell做解析,只会简单按空白字符拆分参数,你写的带转义双引号的Header参数会被拆成两个独立片段:"Content-Type:和application/json",多余的双引号会被当成参数内容传给curl,最终请求携带的Content-Type头格式非法,Spring无法识别为application/json类型,直接返回415错误。

这类传完整字符串给exec方法的坑非常常见,只要参数里带空格、引号,基本都会出现和终端执行结果不一致的问题。

纯Java代码实现方案

不要依赖外部curl命令,直接使用Spring生态自带的HTTP客户端调用接口即可,稳定性更高,也没有命令解析的坑。

方案1:使用RestTemplate实现(兼容所有Spring Boot版本)

直接在监听器中发起HTTP请求,不需要依赖任何外部命令行工具:

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class StartupRefreshListener {

    private final RestTemplate restTemplate = new RestTemplate();

    @EventListener(ApplicationReadyEvent.class)
    public void runAfterStartup() {
        System.out.println("应用启动完成,开始触发refresh端点调用");
        
        // 组装请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 传入空JSON作为请求体
        HttpEntity<String> request = new HttpEntity<>("{}", headers);
        
        try {
            ResponseEntity<String> response = restTemplate.postForEntity(
                    "http://localhost:8081/actuator/refresh",
                    request,
                    String.class
            );
            System.out.println("refresh接口调用成功,返回内容:" + response.getBody());
        } catch (Exception e) {
            System.err.println("refresh接口调用失败:" + e.getMessage());
        }
    }
}

提示:如果服务端口是通过配置文件设置的,不要硬编码8081,可以通过@Value("${server.port:8081}")注入配置值,适配不同环境。

方案2:保留curl调用的修正方式

如果有特殊原因必须调用系统curl命令,不要传入拼接好的完整命令字符串,改用exec(String[] cmdarray)重载,手动拆分每个参数,避免Java自动拆分参数出错:

@EventListener(ApplicationReadyEvent.class)
public void runAfterStartup() throws IOException, InterruptedException {
    System.out.println("应用启动完成,通过curl触发refresh端点");
    // 手动拆分每一个参数,参数值不要额外包裹转义引号
    String[] command = new String[]{
            "curl",
            "localhost:8081/actuator/refresh",
            "-d", "{}",
            "-H", "Content-Type: application/json"
    };

    Process proc = Runtime.getRuntime().exec(command);

    // 同时读取标准输出和错误输出流,避免缓冲区满导致进程阻塞
    BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    BufferedReader errorReader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    while ((line = errorReader.readLine()) != null) {
        System.err.println(line);
    }

    proc.waitFor();
}

这种方式虽然可以正常运行,但依然不推荐:它依赖系统环境预装curl,不同操作系统的curl参数、路径可能存在差异,进程流处理不当还容易出现阻塞问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:39:53