Asterisk GotoIf未按预期跳转:SIP头转移号拨号计划配置故障
排查Asterisk跨Context跳转静默失败的问题
我来帮你拆解这个拨号计划的跳转问题,结合你说的现象——日志显示GOTO执行了但没到目标、看不到“missing diversion”日志、同Context内用标签跳转正常,大概率是跨Context跳转的语法细节或者变量匹配逻辑出了问题,咱们一步步来:
1. 先检查Goto的语法是否完整
Asterisk的跨Context跳转必须指定三个参数:Goto(context, exten, priority),很多人容易漏写后两个参数,导致跳转失效。比如你要跳到diversion-handler这个Context的起始位置,必须写成:
Goto(diversion-handler, s, 1)
而不是只写Goto(diversion-handler)——这种写法在旧版本里可能会被忽略,或者默认用当前的exten和priority,但如果目标Context没有匹配的exten,就会静默失败。
2. 确认Diversion头的判断逻辑是否正确
你说看不到“missing diversion”的日志,说明你的GotoIf条件判断可能根本没走到else分支,要么是变量获取错了,要么是语法格式不对:
- 首先,获取SIP头的正确写法是
${SIP_HEADER(Diversion)},注意大小写(Asterisk变量名不区分大小写,但SIP头的键名是区分的,比如Diversion和diversion是两个不同的头) - 条件判断的语法要严格遵循Asterisk的规则,判断是否存在Diversion头的正确写法是:
这里的GotoIf($["${SIP_HEADER(Diversion)}" != ""]?diversion-handler,s,1)$[]不能少,引号和空格也不能省——少了任何一个,条件都会判定错误,导致逻辑走偏。 - 如果Diversion头是带格式的(比如
Diversion: <sip:1234@example.com>),你要提取号码的话,得用正则:exten => s,n,Set(DIVERSION_NUM=${REGEX("sip:(.*?)@" ${SIP_HEADER(Diversion)},1)}) exten => s,n,GotoIf($["${DIVERSION_NUM}" != ""]?diversion-handler,s,1)
3. 开启详细日志跟踪跳转流程
光看GOTO执行的日志不够,你需要打开更细的日志来定位问题:
- 启动Asterisk控制台后,执行
core set verbose 5,能看到每一步的优先级执行、变量赋值 - 执行
sip set debug on,可以看到收到的SIP请求里是否真的包含Diversion头,以及Asterisk是否正确解析了这个头 - 这样你就能确认:Diversion头是否被正确读取、
GotoIf的条件判定结果是什么、跳转后是否真的进入了目标Context的优先级1
4. 验证目标Context的匹配规则
如果跳转日志显示已经进入目标Context,但没有后续动作,可能是目标Context的exten不匹配:
- 比如你跳转到
diversion-handler,s,1,但目标Context里没有exten => s,1,...的配置,只有_X.,1,...这种匹配号码的规则,那Asterisk找不到匹配的exten,就会直接挂断,不会有任何提示 - 确保目标Context的起始exten和你跳转时指定的一致(比如都是
s,或者都是来电的号码)
示例正确配置
给你一个参考的配置写法,你可以对比调整:
[from-external] exten => s,1,NoOp(Incoming call from ${CALLERID(num)}) ; 检查Diversion头是否存在,存在则跳转 exten => s,n,GotoIf($["${SIP_HEADER(Diversion)}" != ""]?diversion-handler,s,1) ; 走到这里说明没有Diversion头,打印日志并执行原有逻辑 exten => s,n,NoOp(Missing diversion header for call from ${CALLERID(num)}) exten => s,n,Dial(SIP/100,20) exten => s,n,Hangup() [diversion-handler] exten => s,1,NoOp(Handling diverted call, Diversion header: ${SIP_HEADER(Diversion)}) ; 这里写转移号码对应的处理逻辑 exten => s,n,Dial(SIP/200,20) exten => s,n,Hangup()
最后排查点
如果以上都没问题,检查你的Asterisk版本——部分旧版本的GotoIf语法和变量处理有差异,比如不需要$[]包裹条件,你可以尝试去掉$[]再测试:
GotoIf(${SIP_HEADER(Diversion)}?diversion-handler,s,1)
内容的提问来源于stack exchange,提问作者eran
相关产品推荐
相关产品推荐

