Telegram sendPhoto通过multipart/form-data传图报错400问题
问题背景
我正在实现Telegram Bot的图片发送功能,根据Telegram官方文档说明,sendPhoto接口支持使用multipart/form-data格式上传本地文件。

现有实现代码
// 已确认目标文件真实存在 $file = File::get(Storage::disk('local')->path('test.jpeg')); // 等效于file_get_contents()读取文件内容 // 第一种实现:使用longman/telegram-bot库 $serverResponse = Request::sendPhoto([ 'chat_id' => $this->tg_user_chat_id, 'photo' => $file ]); // 第二种实现:直接用Guzzle发请求,排除库本身的问题 $client = new Client(); $response = $client->post("https://api.telegram.org/$telegram->botToken/sendPhoto", [ 'multipart' => [ [ 'name' => 'photo', 'contents' => $file ], [ 'name' => 'chat_id', 'contents' => $this->tg_user_chat_id ] ] ]); Log::info('_response', ['_' => $response->getBody()]); Log::info(env('APP_URL') . "/storage/$url"); Log::info('response:', ['_' => $serverResponse->getResult()]); Log::info('ok:', ['_' => $serverResponse->getOk()]); Log::info('error_code:', ['_' => $serverResponse->getErrorCode()]); Log::info('raw_data:', ['_' => $serverResponse->getRawData()]);
报错现象
两种实现方式返回完全一致的错误响应:
{"ok":false,"error_code":400,"description":"Bad Request: invalid file HTTP URL specified: Wrong URL host"}
目前通过文件ID、公网URL传图的方式均可正常运行,仅本地文件上传路径报错。
问题原因与修复方案
报错核心原因是两种写法都没有正确标识上传的内容为本地文件,Telegram服务端收到photo字段的内容后,默认将其识别为URL/文件ID字符串做解析,最终触发URL格式非法错误。
- 针对Guzzle直接调用的写法:不要提前读取文件二进制内容传入,改为传入
fopen打开的文件资源句柄,同时显式指定上传文件名,Guzzle会自动按文件附件格式组装multipart请求:
$client = new Client(); $response = $client->post("https://api.telegram.org/$telegram->botToken/sendPhoto", [ 'multipart' => [ [ 'name' => 'photo', 'contents' => fopen(Storage::disk('local')->path('test.jpeg'), 'r'), 'filename' => 'test.jpeg' // 必须显式指定文件名,否则不会识别为文件上传 ], [ 'name' => 'chat_id', 'contents' => $this->tg_user_chat_id ] ] ]);
- 针对longman/telegram-bot库的写法:不要传入读取后的文件二进制内容,使用库提供的
encodeFile方法包装本地文件绝对路径,库内部会自动处理文件上传逻辑:
$serverResponse = Request::sendPhoto([ 'chat_id' => $this->tg_user_chat_id, 'photo' => Request::encodeFile(Storage::disk('local')->path('test.jpeg')) ]);
- 补充校验项:
- 确认上传的图片大小不超过Telegram普通图片接口5MB的限制
- 确认文件MIME类型为Telegram支持的jpg/png/gif等图片格式
- 确认程序对目标文件有读取权限,
fopen打开资源时不会返回false
内容的提问来源于stack exchange,提问作者pibocik125
相关产品推荐
相关产品推荐

