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

基于Twilio的呼叫转接触发应用错误12100求助

Twilio呼叫自动化系统Error 12100(文档解析失败)排查与修复

问题概述

开发基于Twilio的呼叫自动化系统,需实现以下功能:

  • 发起外呼呼叫
  • 通话过程中播放音频文件
  • 用户按下“1”时转接至指定号码

运行代码时通话出现“应用错误”,Twilio调试器显示错误码12100,对应文档解析失败,问题源于TwiML的生成与返回逻辑存在缺陷。

错误原因分析

  1. 初始TwiML地址为空:发起呼叫时url参数未设置,Twilio无法获取初始通话流程的TwiML文档
  2. Gather动作地址缺失:<Gather>标签的action属性为空,用户按键后Twilio无法找到处理请求的端点
  3. 响应内容混杂:handleKeyPress函数中先输出文本信息,再输出TwiML,导致响应内容不符合XML规范,Twilio无法解析
  4. 未指定请求方法:<Gather>未明确method="POST",可能导致Twilio无法正确传递按键数据

修复方案

  1. 填充呼叫初始化时的url参数,指向服务器上返回初始TwiML的接口地址
  2. 为<Gather>标签设置action属性和method="POST",指定按键处理接口
  3. 移除handleKeyPress中的非XML输出文本,确保响应仅返回标准TwiML
  4. 确保所有Twilio凭据、目标号码、音频URL等变量已正确填充
  5. 验证TwiML输出前无任何多余字符(如空格、换行),保证XML结构完整

修正后的完整代码

<?php
// Enable error reporting for debugging
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require 'vendor/autoload.php'; // Include Twilio SDK
use Twilio\Rest\Client;

// Twilio credentials - 请填充实际值
$twilioSid = 'your_twilio_sid'; // Your Twilio SID
$twilioToken = 'your_twilio_auth_token'; // Your Twilio Auth Token
$twilioFromNumber = 'your_twilio_phone_number'; // Your Twilio phone number
$forwardNumber = 'your_forward_number'; // Number to forward to if '1' is pressed
$audioFileUrl = 'your_audio_file_url'; // URL of your audio file
$baseUrl = 'https://your-domain.com/your-script.php'; // 替换为你的脚本访问地址

// Function to start the call
function startCalling() {
    global $twilioSid, $twilioToken, $twilioFromNumber, $baseUrl;

    // Phone numbers to call - 填充实际呼叫号码
    $numbersToCall = ['target_phone_number']; // Example number

    // Create a Twilio client
    $client = new Client($twilioSid, $twilioToken);

    foreach ($numbersToCall as $toPhoneNumber) {
        try {
            // Initiate the call and listen for keypresses
            $call = $client->calls->create(
                $toPhoneNumber,  // To
                $twilioFromNumber,  // From
                [
                    'url' => $baseUrl . '?action=serve_twiml', // 指向初始TwiML接口
                ]
            );
            echo "Call initiated to: " . $toPhoneNumber . " with SID: " . $call->sid . "<br>";
        } catch (Exception $e) {
            echo "Error while calling " . $toPhoneNumber . ": " . $e->getMessage() . "<br>";
        }
    }
}

// Function to serve TwiML
function serveTwiml() {
    global $audioFileUrl, $baseUrl;

    // 确保在输出XML前无任何内容
    ob_clean();
    // Output XML response
    header('Content-Type: text/xml');
    echo '<?xml version="1.0" encoding="UTF-8"?>';
    echo '<Response>';
    // 设置Gather的action和method,指向按键处理接口
    echo '<Gather numDigits="1" action="' . $baseUrl . '?action=handle_key_press" method="POST">';
    echo '<Play>' . htmlspecialchars($audioFileUrl) . '</Play>';
    echo '</Gather>';
    // 用户未按键时的 fallback,重复播放音频
    echo '<Play>' . htmlspecialchars($audioFileUrl) . '</Play>';
    echo '</Response>';
    exit;
}

// Function to handle keypresses
function handleKeyPress() {
    global $forwardNumber, $audioFileUrl;

    $Digits = $_POST['Digits'] ?? '';

    // 确保在输出XML前无任何内容
    ob_clean();
    header('Content-Type: text/xml');
    echo '<?xml version="1.0" encoding="UTF-8"?>';
    
    if ($Digits == '1') {
        // 直接返回Dial的TwiML,无需通过API更新呼叫(更高效)
        echo '<Response><Dial>' . htmlspecialchars($forwardNumber) . '</Dial></Response>';
    } else {
        // 未按1时,返回重新播放音频的TwiML
        echo '<Response><Gather numDigits="1" action="' . $_SERVER['REQUEST_URI'] . '" method="POST">';
        echo '<Play>' . htmlspecialchars($audioFileUrl) . '</Play>';
        echo '</Gather></Response>';
    }
    exit;
}

// Handle POST requests
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_GET['action'])) {
        switch ($_GET['action']) {
            case 'handle_key_press':
                handleKeyPress();
                break;
        }
    } elseif (isset($_POST['action'])) {
        switch ($_POST['action']) {
            case 'start_calling':
                startCalling();
                break;
        }
    }
}

// Handle GET requests for serving TwiML
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action'])) {
    if ($_GET['action'] === 'serve_twiml') {
        serveTwiml();
    }
}
?>

额外说明

  • 替换代码中所有标注请填充实际值的变量,确保Twilio凭据、号码、音频URL、脚本访问地址正确
  • 使用ob_clean()清除输出缓冲区,避免意外的空白字符破坏XML结构
  • 按键处理时直接返回TwiML而非通过API更新呼叫,更符合Twilio的流程设计,也减少了出错概率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:10:56