可以藉由Agora控制台手動建立房間以及該房間的Token,讓使用者可以藉著這個Token去呼叫Join()的Function,實現加入房間的功能。
但若是每次都手動建立,這樣則過於麻煩,一來是我要新的房間就必須自己輸入一次房間的名稱,二來是Token一天後就會過期,又要重新再建一筆。
因此,我們需要一個後端服務替我們取得特定房間的Token。這樣當我們有加入房間的需求時,只要呼叫API替我們建立,而不用手動建立,也不需要煩惱Token過期的問題。
本文前置:需要一可以佈署至Heroku之含有NodeJS Server的Angular專案,以及Agora控制台已存在項目。
本文重點:傳入房間及是否為發布者,回傳UID與TOKEN給前端
分成幾個部分來說明
- Server API
- 測試 API 是否正常 (Postman)
- 前端 取得 API 資料
- 補充
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://...']
補充
- 透過buildTokenWithUid()建立的Token,在join到agora的channel時必須要帶入當初帶進buildTokenWithUid()的uid,因為這個Token是根據該uid產生的,否則會報錯
- 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網址。