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

PHP开发Discord Bot遇交互失败问题求助

Discord Bot PHP开发:交互失败问题排查

我用PHP开发Discord Bot,URL验证配置正常,相关命令已创建。在Discord调用命令时,PHP能接收请求并回复,但Discord始终提示“交互失败”。返回的JSON格式看似符合要求,不清楚哪里出了问题。

相关代码如下:

$payload = file_get_contents('php://input');
endpointVerify($_SERVER, $payload, 'xpto');

function endpointVerify(array $headers, string $payload, string $publicKey)
{
    if (
        !isset($headers['HTTP_X_SIGNATURE_ED25519'])
        || !isset($headers['HTTP_X_SIGNATURE_TIMESTAMP'])
    )
        return ['code' => 401, 'payload' => null];

    $signature = $headers['HTTP_X_SIGNATURE_ED25519'];
    $timestamp = $headers['HTTP_X_SIGNATURE_TIMESTAMP'];

    if (!trim($signature, '0..9A..Fa..f') == '')
        return ['code' => 401, 'payload' => null];

    $message = $timestamp . $payload;
    $binarySignature = sodium_hex2bin($signature);
    $binaryKey = sodium_hex2bin($publicKey);

    if (!sodium_crypto_sign_verify_detached($binarySignature, $message, $binaryKey))
        return ['code' => 401, 'payload' => null];

    $payload = json_decode($payload, true);
    switch ($payload['type'])
    {
        // Verification
        case 1:
            $result = ['code' => 200, 'payload' => ['type' => 1]];
            http_response_code($result['code']);
            echo json_encode($result['payload']);
            break;

        // Bot messages
        case 2:
            $body = [
                'code' => 200, 
                'payload' => [
                    'type' => 5
                ]
            ];
            http_response_code($body['code']);
            echo json_encode($body['payload']);

            if ($payload["data"]["name"] == 'lfg')
            {
                $body = [
                    'code' => 200, 
                    'payload' => [
                        'type' => 4, 
                        'data' => [
                            "tts" => False,
                            "content" => "Message to test reply to discord",
                            "embeds" => [],
                            "allowed_mentions" => [
                                "parse" => []
                            ]
                        ]
                    ]
                ];
                http_response_code($body['code']);
                echo json_encode($body['payload']);
            }
            else
            {
                $result = ['code' => 200, 'payload' => ['type' => 2]];
                http_response_code($result['code']);
                echo json_encode($result['payload']);
                
            }
            break;

        default:
            $result = ['code' => 400, 'payload' => null];
            http_response_code($result['code']);
            echo json_encode($result['payload']);
    }
}

问题诊断与修复

1. 重复输出响应内容

在case 2分支中,你先输出了type:5的响应,之后又输出了另一组响应(type:4或type:2)。Discord要求每个交互请求只能返回一个合法响应,多次输出会导致JSON格式损坏,直接触发交互失败。

2. 布尔值大小写错误

PHP中布尔值是小写的false,但代码里写了False(大写F),json_encode后会被转为字符串"False",不符合Discord API要求的布尔类型。

3. 签名格式验证逻辑错误

trim($signature, '0..9A..Fa..f')的写法无效,trim的第二个参数是字符列表而非范围,应该用正则表达式验证签名是否为十六进制格式。

修复后的代码

$payload = file_get_contents('php://input');
endpointVerify($_SERVER, $payload, 'xpto');

function endpointVerify(array $headers, string $payload, string $publicKey)
{
    if (
        !isset($headers['HTTP_X_SIGNATURE_ED25519'])
        || !isset($headers['HTTP_X_SIGNATURE_TIMESTAMP'])
    ) {
        http_response_code(401);
        exit;
    }

    $signature = $headers['HTTP_X_SIGNATURE_ED25519'];
    $timestamp = $headers['HTTP_X_SIGNATURE_TIMESTAMP'];

    // 正确验证签名为十六进制格式
    if (!preg_match('/^[0-9a-fA-F]+$/', $signature)) {
        http_response_code(401);
        exit;
    }

    $message = $timestamp . $payload;
    $binarySignature = sodium_hex2bin($signature);
    $binaryKey = sodium_hex2bin($publicKey);

    if (!sodium_crypto_sign_verify_detached($binarySignature, $message, $binaryKey)) {
        http_response_code(401);
        exit;
    }

    $payloadData = json_decode($payload, true);
    switch ($payloadData['type']) {
        // 验证请求
        case 1:
            http_response_code(200);
            echo json_encode(['type' => 1]);
            break;

        // 应用命令交互
        case 2:
            if ($payloadData["data"]["name"] == 'lfg') {
                // 直接返回最终响应,无需先返回type:5(仅异步处理时需要)
                $response = [
                    'type' => 4,
                    'data' => [
                        "tts" => false, // 修正为小写布尔值
                        "content" => "Message to test reply to discord",
                        "embeds" => [],
                        "allowed_mentions" => [
                            "parse" => []
                        ]
                    ]
                ];
                http_response_code(200);
                header('Content-Type: application/json');
                echo json_encode($response);
            } else {
                http_response_code(200);
                header('Content-Type: application/json');
                echo json_encode(['type' => 2]);
            }
            break;

        default:
            http_response_code(400);
            header('Content-Type: application/json');
            echo json_encode(['error' => 'Unknown interaction type']);
    }
}

额外注意事项

  • 仅当需要执行耗时操作时,才需要先返回type:5(延迟响应),之后通过Webhook发送后续消息;同步响应直接返回type:4(带内容回复)或type:2(确认交互)即可。
  • 必须添加Content-Type: application/json响应头,确保Discord能正确解析返回内容。
  • 确认PHP的sodium扩展已启用,签名验证失败也会导致交互异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:27:54