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

基于ASP.NET Core Web API与Angular实现Twilio外呼手机的技术问询

管理员呼叫用户手机解决方案(Angular + ASP.NET Core + Twilio)

一、后端ASP.NET Core Web API改造

1. 替换呼叫创建的回调URL

原代码使用的Twilio Demo XML仅作演示,需替换为自定义API端点,用于处理用户接听后的通话桥接逻辑:

string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");
string twilioNumber = Environment.GetEnvironmentVariable("TWILIO_PHONE_NUMBER");

TwilioClient.Init(accountSid, authToken);

var call = CallResource.Create(
        url: new Uri($"{Request.Scheme}://{Request.Host}/api/voice/handle-call"),
        to: new Twilio.Types.PhoneNumber("用户手机号"),
        from: new Twilio.Types.PhoneNumber(twilioNumber)
);

Console.WriteLine(call.Sid);

2. 实现通话处理API(用户接听后触发)

编写API返回TwiML指令,告知Twilio将用户通话桥接到管理员终端(软电话或手机):

[ApiController]
[Route("api/voice")]
public class VoiceController : ControllerBase
{
    [HttpGet("handle-call")]
    public IActionResult HandleIncomingCall()
    {
        var response = new Twilio.TwiML.VoiceResponse();
        // 桥接到管理员的Twilio Client身份(若用软电话)
        response.Dial(new Dial { CallerId = Request.Query["From"] }).Client("admin");
        // 若管理员用固定手机号,替换为:
        // response.Dial(new Dial { CallerId = Request.Query["From"] }).Number("管理员手机号");

        return Content(response.ToString(), "application/xml");
    }
}

3. 前端调用的发起呼叫API

暴露接口供Angular触发呼叫请求:

[HttpPost("initiate-call")]
public IActionResult InitiateCall([FromBody] CallRequest request)
{
    string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
    string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");
    string twilioNumber = Environment.GetEnvironmentVariable("TWILIO_PHONE_NUMBER");

    TwilioClient.Init(accountSid, authToken);

    var call = CallResource.Create(
        url: new Uri($"{Request.Scheme}://{Request.Host}/api/voice/handle-call"),
        to: new Twilio.Types.PhoneNumber(request.UserPhoneNumber),
        from: new Twilio.Types.PhoneNumber(twilioNumber)
    );

    return Ok(new { CallSid = call.Sid });
}

public class CallRequest
{
    public string UserPhoneNumber { get; set; }
}

4. 生成Twilio认证Token的API

为Angular端的软电话生成认证Token:

[HttpGet("get-token")]
public IActionResult GetToken(string identity)
{
    string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
    string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");
    string twilioApiKey = Environment.GetEnvironmentVariable("TWILIO_API_KEY");
    string twilioApiSecret = Environment.GetEnvironmentVariable("TWILIO_API_SECRET");

    var token = new Twilio.Jwt.AccessToken(
        accountSid,
        twilioApiKey,
        twilioApiSecret,
        identity: identity
    );

    var grant = new Twilio.Jwt.AccessToken.VoiceGrant
    {
        OutgoingApplicationSid = "你的TwiML应用SID", // Twilio控制台创建的TwiML应用SID
        IncomingAllow = true
    };

    token.AddGrant(grant);

    return Ok(new { Token = token.ToJwt() });
}

二、Angular前端实现

1. 安装依赖

npm install @twilio/voice-sdk

2. 核心组件代码

实现软电话初始化、呼叫触发、通话控制:

import { Component, OnInit } from '@angular/core';
import { Voice } from '@twilio/voice-sdk';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-admin-call',
  templateUrl: './admin-call.component.html',
  styleUrls: ['./admin-call.component.css']
})
export class AdminCallComponent implements OnInit {
  private voiceClient: Voice | null = null;
  currentCall: any = null;
  userPhoneNumber = '';

  constructor(private http: HttpClient) { }

  ngOnInit(): void {
    this.initTwilioClient();
  }

  async initTwilioClient(): Promise<void> {
    const tokenResp = await this.http.get<{ Token: string }>('/api/voice/get-token?identity=admin').toPromise();
    if (tokenResp?.Token) {
      this.voiceClient = new Voice(tokenResp.Token);
      // 监听来电(用户接听后Twilio会呼叫管理员软电话)
      this.voiceClient.on('incoming', (call) => {
        call.accept();
        this.currentCall = call;
        call.on('disconnect', () => this.currentCall = null);
      });
    }
  }

  async initiateCall(): Promise<void> {
    if (!this.userPhoneNumber || !this.voiceClient) return;
    await this.http.post('/api/voice/initiate-call', { UserPhoneNumber: this.userPhoneNumber }).toPromise();
  }

  hangUp(): void {
    this.currentCall?.disconnect();
    this.currentCall = null;
  }

  toggleMute(): void {
    this.currentCall?.mute(!this.currentCall.isMuted);
  }
}

3. 组件模板

<div class="call-panel">
  <input type="text" [(ngModel)]="userPhoneNumber" placeholder="输入用户手机号" />
  <button (click)="initiateCall()" [disabled]="currentCall">发起呼叫</button>
  <button (click)="hangUp()" [disabled]="!currentCall">挂断</button>
  <button (click)="toggleMute()" [disabled]="!currentCall">
    {{ currentCall?.isMuted ? '取消静音' : '静音' }}
  </button>
  <div *ngIf="currentCall" class="call-status">通话中...</div>
</div>

三、关键逻辑说明

  • 用户接听后处理:Twilio会自动调用handle-call API,返回的TwiML通过<Dial>指令将用户手机与管理员终端桥接,实现双向通话。
  • 双向通信核心:管理员端通过Twilio Client SDK实现软电话,依赖后端生成的Token完成Twilio认证,通话由Twilio负责中转。
  • 环境变量配置:确保后端配置Twilio的Account SID、Auth Token、API Key、API Secret、Twilio号码、TwiML应用SID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:20:07