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
相关产品推荐
相关产品推荐

