Salesforce Bulk API批量任务Java调用报错求助(Postman正常)
这个问题我太熟悉了!Salesforce Bulk API对Content-Type的格式要求特别苛刻,它只接受纯text/csv,不允许带任何额外参数(比如charset=utf-8)。而你的Java HTTP客户端默认会自动给text/csv类型加上charset=utf-8后缀,这就是触发409错误的根源——Postman没加这个参数,所以能正常运行。
问题拆解
错误提示已经说得很明确:Wrong content-type for batch (text/csv; charset=utf-8), job is of type: text/csv,意思是你发送的请求头里Content-Type是text/csv; charset=utf-8,但任务要求的是纯text/csv。Java的各类HTTP库(不管是原生的HttpURLConnection、Spring的RestTemplate还是Apache HttpClient)都会默认给文本类型的请求体追加字符集参数,这就是问题所在。
具体解决方案
核心就是强制让请求的Content-Type严格等于text/csv,不要带任何字符集后缀。下面针对常用的Java HTTP客户端给出实现:
1. 原生HttpURLConnection实现
URL uploadUrl = new URL("你的批量任务上传地址"); HttpURLConnection conn = (HttpURLConnection) uploadUrl.openConnection(); conn.setRequestMethod("POST"); // 设置授权Token conn.setRequestProperty("Authorization", "Bearer " + yourAccessToken); // 关键:直接设置Content-Type为text/csv,不要让系统自动追加charset conn.setRequestProperty("Content-Type", "text/csv"); conn.setDoOutput(true); // 用UTF-8编码CSV内容,但不在请求头里声明字符集 try (OutputStream outputStream = conn.getOutputStream()) { byte[] csvBytes = yourCsvString.getBytes(StandardCharsets.UTF_8); outputStream.write(csvBytes); } // 处理响应逻辑... int responseCode = conn.getResponseCode(); // 可以打印请求头验证:System.out.println(conn.getRequestProperty("Content-Type"));
2. Spring RestTemplate实现
默认的StringHttpMessageConverter会自动添加charset,所以我们需要替换成自定义的转换器:
RestTemplate restTemplate = new RestTemplate(); // 移除默认的String转换器 restTemplate.getMessageConverters().removeIf(converter -> converter instanceof StringHttpMessageConverter); // 添加自定义的CSV转换器,指定Content-Type为text/csv且不附加charset StringHttpMessageConverter csvConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8); csvConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.valueOf("text/csv"))); restTemplate.getMessageConverters().add(csvConverter); // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + yourAccessToken); headers.setContentType(MediaType.valueOf("text/csv")); HttpEntity<String> requestEntity = new HttpEntity<>(yourCsvString, headers); ResponseEntity<String> response = restTemplate.postForEntity("你的批量任务上传地址", requestEntity, String.class);
3. Apache HttpClient实现
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost("你的批量任务上传地址"); // 设置授权头和Content-Type httpPost.setHeader("Authorization", "Bearer " + yourAccessToken); httpPost.setHeader("Content-Type", "text/csv"); // 构造请求体,用UTF-8编码但明确设置Content-Type为text/csv StringEntity csvEntity = new StringEntity(yourCsvString, StandardCharsets.UTF_8); csvEntity.setContentType("text/csv"); httpPost.setEntity(csvEntity); // 执行请求 try (CloseableHttpResponse response = httpClient.execute(httpPost)) { // 处理响应... }
验证小技巧
可以在代码里打印实际发送的Content-Type头,确认它确实是text/csv而不是带charset的版本。比如用conn.getRequestProperty("Content-Type")(原生连接)或者查看日志工具里的请求详情。
内容的提问来源于stack exchange,提问作者eshu indhu

