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

PHP中带附件的消息无法发送至Discord的技术求助

解决Discord API发送带附件PDF的400错误问题

你的问题出在错误构建了multipart/form-data请求,Discord的带附件消息要求请求采用多部分表单格式,但你之前的写法要么把文件对象塞进JSON(无法序列化),要么错误地设置请求头并直接发送JSON字符串,导致Discord无法识别有效内容,返回"Cannot send an empty message"。

正确实现代码

使用Guzzle的multipart选项来构建请求,这是处理文件上传的标准方式,Guzzle会自动处理Content-Type和边界等细节:

$discordBaseUrl = 'https://discord.com/api';
$channelId = '1882390272832675344';
// 注意:服务器上要使用Laravel的storage_path获取正确路径,不要用本地C盘路径
$payrollPath = storage_path('app/payrolls/306_payroll.pdf');
$fileName = pathinfo($payrollPath)['filename'] . '.pdf';

$httpClient = new Client([
    'verify' => false,
    'headers' => [
        'Authorization' => config('local.discord_token'),
        'Accept' => 'application/json',
    ],
]);

$response = $httpClient->post("$discordBaseUrl/channels/$channelId/messages", [
    'multipart' => [
        // 第一个部分:消息内容的JSON payload
        [
            'name' => 'payload_json',
            'contents' => json_encode([
                'content' => 'A payroll has been sent to you.',
                'attachments' => [
                    [
                        'id' => 0, // 对应下面files[0]的索引
                        'description' => 'Payroll description.',
                        'filename' => $fileName
                    ]
                ]
            ], JSON_UNESCAPED_UNICODE)
        ],
        // 第二个部分:要上传的PDF文件
        [
            'name' => 'files[0]', // 索引要和attachments里的id一致
            'contents' => fopen($payrollPath, 'r'),
            'filename' => $fileName,
            'headers' => [
                'Content-Type' => 'application/pdf'
            ]
        ]
    ]
]);

$responseBody = $response->getBody()->getContents();

关键修正点

  • 不要手动设置Content-Type: multipart/form-data:Guzzle在使用multipart选项时会自动生成正确的Content-Type(包含边界字符串),手动设置会破坏请求格式。
  • 拆分payload和文件:payload_json字段存消息的JSON内容,files[N]字段存文件流,两者通过attachments里的id关联(id=N对应files[N])。
  • 文件路径修正:服务器上不能用本地Windows路径,改用Laravel的storage_path()函数获取正确的存储文件路径。
  • 不要用json_encode处理整个请求体:multipart请求的每个部分都是独立的,文件部分需要传入文件流而非序列化对象。

为什么之前的代码失败

  1. 第一段代码:把curl_file_create生成的对象塞进JSON,JSON无法序列化CURLFile对象,导致Discord收到的内容无效,判定为空消息。
  2. 第二段代码:错误设置Content-Disposition请求头,且直接发送JSON字符串作为请求体,Discord无法解析multipart格式,依然判定消息为空。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:47:19