【實作紀錄】Agora × Angular 獲取Token API

Ray
9 min readOct 19, 2021

--

可以藉由Agora控制台手動建立房間以及該房間的Token,讓使用者可以藉著這個Token去呼叫Join()的Function,實現加入房間的功能。

但若是每次都手動建立,這樣則過於麻煩,一來是我要新的房間就必須自己輸入一次房間的名稱,二來是Token一天後就會過期,又要重新再建一筆。

因此,我們需要一個後端服務替我們取得特定房間的Token。這樣當我們有加入房間的需求時,只要呼叫API替我們建立,而不用手動建立,也不需要煩惱Token過期的問題。

本文前置:需要一可以佈署至Heroku之含有NodeJS Server的Angular專案,以及Agora控制台已存在項目。

本文重點:傳入房間及是否為發布者,回傳UID與TOKEN給前端

分成幾個部分來說明

  1. Server API
  2. 測試 API 是否正常 (Postman)
  3. 前端 取得 API 資料
  4. 補充

Server API

預期將API建立於”/rtctoken”路徑下,這邊用node.js來建立我們的後端。

安裝套件

npm install agora-access-token 
//為了可以使用相關方法(產生Token及UID..等等)
npm install body-parser
//讓可以透過req.body傳入值(沒有import這個的話,req.body會是undefined)

引入套件

const bodyParser = require(‘body-parser’)const Agora = require(“agora-access-token”);

使用Body-Parser

app.use(bodyParser.urlencoded({ extended: false }))app.use(bodyParser.json())

buildTokenWithUid()說明

透過剛剛Import的agora-access-token其中提供的Function來建立Token

RtcTokenBuilder.buildTokenWithUid()

buildTokenWithUid()總共有六個參數,分別是

appID, appCertificate, channel, uid, role, privilegeExpiredTs
  • appID : 項目的唯一ID
  • appCertificate:項目的證書(主要證書或次要證書)
  • channel:欲建立的頻道名稱(呼叫這支API時傳入)
  • uid:同頻道內必須是唯一的(否則後進的會把前進的踢掉)
  • role:RtcRole.PUBLISHER(發布者) 或 RtcRole.SUBSCRIBER(訂閱者)
  • privilegeExpiredTs:到期時間

補充:role的部分,除非是直播才有分發布者或訂閱者,不然一般有推出自己影音流的需求都是屬於發布者

核心程式碼

app.post(“/rtctoken”, (req, res) => {  console.log(‘收到參數’,req.body)
const appID = “你的AppID”; const appCertificate = “你的證書”; const uid = Math.floor(Math.random() * 100000);
const currentTimestamp = Math.floor(Date.now() / 1000);
const expirationTimeInSeconds = 3600;
const privilegeExpiredTs = currentTimestamp + expirationTimeInSeconds;
const role = req.body.isPublisher ? Agora.RtcRole.PUBLISHER : Agora.RtcRole.SUBSCRIBER; const channel = req.body.channel; const token = Agora.RtcTokenBuilder.buildTokenWithUid(appID, appCertificate, channel, uid, role, privilegeExpiredTs);
console.log(‘回傳參數 uid:’ + uid + ‘,token:’ + token)
res.send({ uid, token });});

測試 API 是否正常 (Postman)

透過Postman的POST方法,在Body格式選擇"raw"以及"JSON",將參數帶入

{  “channel”:”Test11",  “isPublisher”:true}

成功拿到回傳值,API works!

{  “uid”: 66659,  “token”:   “00687bcb49754774c968b5f2c40ed4da5beIABotzuRsKqXF8HTHPZquIY4hqkJduaqd+mxivzZVK4+zgnb/sraztHgIgD5al2T3gZwYQQAAQBuw25hAgBuw25hAwBuw25hBABuw25h”}

前端取得 API 資料

透過Postman我們知道API現在是正常運作的,接下來的目標就是不使用Postman,改由前端實際串接後端並檢查是否正常。

我們要透過Angular提供的HttpClient來拿剛剛建立的API資料

首先需要在app.module引入HttpClientModule,並加到imports陣列中

app.module.tsimport { HttpClientModule } from ‘@angular/common/http’;

imports: [
... HttpClientModule],

接著建立一個Service,負責使用Http.post

this.http.post<>(API的URL, 傳入的資料, HTTP設定)

核心程式碼

apiTest(){let data = {  “channel”:”Test11",  “isPublisher”:true}const httpOptions = {  headers: new HttpHeaders({  ‘Content-Type’: ‘application/json’,})};  this.http.post<any>(‘http://localhost:8080/rtctoken', data, httpOptions).subscribe(res=>{    console.log('資料回傳',res)  })}

接著我們呼叫這個Function,看看是否取得資料。會發現報錯

這是因為同源政策的關係,因此無法取得跨來源資料(CORS)。若沒有這個政策,則網路上大家都可以隨意存取或操作其他人的資料,若請求的來源是你信任的網站,則可以透過Header的設定來規範哪些來源可以被存取,也可以使用萬用網址符號"*"來開放來自所有網址的存取權(大多公共API都是這樣)。

下面提供解決方法,回到Server.js

npm install cors // 讓我們方便的設定cors

使用方法

var cors = require('cors');var corsOptions = {  origin: 'http://localhost:4200' }app.use(cors(corsOptions));

同源政策不允許不同Port進行資料共享,即便是同一個BaseUrl,上面這段Code的意思是開放angular serve起來的4200 port 能夠存取這支API。

options裡面的參數,可以是陣列。

origin: ['http://...', 'http://...']

補充

  1. 透過buildTokenWithUid()建立的Token,在join到agora的channel時必須要帶入當初帶進buildTokenWithUid()的uid,因為這個Token是根據該uid產生的,否則會報錯
  2. Post的網址記得要根據當前的BaseURL變動,例如在本地端執行時
this.http.post<any>(‘http://localhost:8080/rtctoken'...)

佈署至Heroku則須改為

this.http.post<any>(‘https://<專案名稱>.herokuapp.com/rtctoken'...)

可以透過下面這個方法取得當前BaseURL

${window.location.hostname}

不過還是需要注意Local(HTTP)及Heroku(HTTPS)的差別,因此推薦的方法是根據Environment(dev. 或 prod.)的不同來選擇要Post過去的API網址。

--

--

No responses yet