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

Spring Boot中RestTemplate调用Telegram API sendDocument报错解决

使用RestTemplate调用Telegram API发送PDF文件的正确方式

问题背景

使用Spring Boot 3.1、Telegram Bots Spring Boot Starter 6.7.0搭建WebHook机器人,业务要求必须通过RestTemplate调用Telegram API的/sendDocument接口发送二进制PDF文件。之前编写的RestTemplate代码触发Telegram API 400错误:

{"ok":false,"error_code":400,"description":"Bad Request: invalid file HTTP URL specified: Unsupported URL protocol"}
同时伴随空指针异常:Cannot invoke "org.telegram.telegrambots.meta.api.objects.Message.getChatId()" because the return value of "org.telegram.telegrambots.meta.api.objects.Update.getMessage()" is null。

改用Apache HttpClient或正确的WebClient代码可正常运行,但需要适配RestTemplate实现。

错误原因

之前的代码错误使用了Telegram SDK的InputFile对象作为Multipart请求体的文件参数。RestTemplate无法正确序列化InputFile,导致请求体中传递的是InputFile的toString()值(类似文件URL格式),而非实际的二进制文件内容,触发Telegram API的参数格式错误。

解决方案

RestTemplate处理Multipart文件上传时,需要使用Spring的FileSystemResource或ClassPathResource直接包装文件,而非Telegram SDK的InputFile。同时确保RestTemplate的配置支持Multipart请求(Spring Boot默认配置已支持,但如果是自定义RestTemplate需确保包含MultipartMessageConverter)。

正确代码实现

1. 基础RestTemplate调用代码

import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

public void sendPdfViaRestTemplate(Long chatId, String botToken) {
    String apiUrl = "https://api.telegram.org/bot" + botToken + "/sendDocument";
    
    // 可注入Spring容器中配置好的RestTemplate,无需手动实例化
    RestTemplate restTemplate = new RestTemplate();
    
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
    
    MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
    body.add("chat_id", chatId);
    
    // 使用ClassPathResource读取classpath下的PDF文件
    try {
        ClassPathResource pdfResource = new ClassPathResource("reports/report.pdf");
        body.add("document", pdfResource);
    } catch (IOException e) {
        throw new RuntimeException("Failed to load PDF file", e);
    }
    
    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
    
    // 执行请求,可根据业务需求替换返回类型(如Telegram官方API的响应对象)
    String response = restTemplate.postForObject(apiUrl, requestEntity, String.class);
    System.out.println("Telegram API Response: " + response);
}

2. 自定义RestTemplate配置(可选)

如果需要自定义RestTemplate(如设置超时、添加拦截器),需确保配置MultipartMessageConverter以支持Multipart请求:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.multipart.MultipartMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        
        // 确保MultipartMessageConverter存在(Spring Boot默认已包含,此处为显式配置示例)
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        boolean hasMultipartConverter = converters.stream()
                .anyMatch(converter -> converter instanceof MultipartMessageConverter);
        
        if (!hasMultipartConverter) {
            converters.add(new MultipartMessageConverter());
        }
        
        // 可添加其他配置,比如设置请求超时
        // SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // factory.setConnectTimeout(5000);
        // factory.setReadTimeout(10000);
        // restTemplate.setRequestFactory(factory);
        
        return restTemplate;
    }
}

注意事项

  • 禁止使用Telegram SDK的InputFile作为RestTemplate的Multipart参数,必须直接使用Spring的Resource实现类传递文件内容。
  • 若文件存储在本地磁盘而非classpath下,改用FileSystemResource包装文件路径:
    body.add("document", new FileSystemResource("/path/to/your/report.pdf"));
    
  • 空指针异常与WebHook的Update对象解析有关,需在WebHook处理代码中添加空值判断:
    if (update.getMessage() != null) {
        Long chatId = update.getMessage().getChatId();
        sendPdfViaRestTemplate(chatId, botToken);
    } else {
        // 处理无Message的Update(如回调查询等)
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:54:59