在函數計算中,您可以通過配置HTTP觸發器讓函數響應WebSocket請求。當HTTP觸發器配置完成后,相關聯的函數便能夠作為一個Web Server,對WebSocket請求進行處理,并將處理結果返回給請求端。
前提條件
步驟一:創建函數
步驟二:編寫并部署代碼
在函數詳情頁面,單擊函數代碼頁簽,在代碼編輯器中編寫代碼。
在控制臺WebIDE的當前目錄,將下面的代碼復制到index.js文件中。代碼示例如下:
const WebSocket = require('ws'); const WebSocketServer = WebSocket.Server; const wss = new WebSocketServer({ host: "0.0.0.0", port: 9000, }); wss.on('connection', function (ws, req) { console.log(`[SERVER] connection()`); ws.on('message', function (message) { ws.send(`${message}`, (err) => { if (err) { console.log(`[SERVER] error: ${err}`); } }); }) });
說明WebSocket Server監聽的IP地址是
0.0.0.0
,表示服務器將監聽所有可用的網絡接口。IP地址不能設置為127.0.0.1
或localhost
。WebSocket Server監聽的端口號是一個介于0到65535之間的整數,通常會選擇一個大于1024的整數。這里
port
的值需要設置為您在創建函數時配置的監聽端口,默認值為9000
端口。
此時,WebIDE的目錄結構如下圖所示:
在WebIDE的終端窗口,執行
npm install ws
命令來安裝依賴。安裝完成后,會自動生成文件package-lock.json,目錄結構如下圖所示:
單擊部署代碼,將您的代碼部署到函數計算中。
步驟三:測試函數
在函數詳情頁面,單擊觸發器管理頁簽,查看并復制觸發器的公網訪問地址。
說明HTTP觸發器創建成功后,訪問地址不會變更。
使用Postman來測試函數的正確性。更多信息,請參見Postman。
在Postman中創建WebSocket請求。
將該URL復制到Postman中,并將Scheme由HTTPS變更成WSS。
根據需求配置Params及Headers。
連接WebSocket,連接成功后即可以發送消息。
輸入要發送的消息并進行發送,然后查看消息接收的情況。
超過執行超時時間后,會斷開與WebSocket服務器的連接。
測試過程如下圖所示:
(可選)如果您在用Postman工具測試的過程出現FCCommonError的錯誤,請確認您HTTP觸發器的認證方式,如您無需鑒權訪問,可在HTTP觸發器創建時或創建后選擇無需認證進行測試。
更多說明
請求超時
函數計算在執行超時時間上,并不會區分WebSocket請求和HTTP請求。如果您的WebSocket連接存活時間超過了您設置的執行超時時間,WebSocket連接會被強制關閉,您的客戶端會收到1006狀態碼。
連接保活和超時重連
當您的WebSocket連接建立之后,除了在連接時長超過您設置的執行超時時間會斷開連接之外,函數計算不會干涉您的任何邏輯。如果在存續期間,您的WebSocket連接在一段時間內沒有數據傳輸,則該連接可能會被網絡中的中間節點關閉,比如NAT網關(用戶客戶端的內網地址到外網地址的映射)、路由器配置等。這種情況下,連接的具體超時時間不是固定的,如果在超時時間范圍內沒有任何數據傳輸,NAT可能會斷開該WebSocket連接,您可能需要通過WebSocket協議提供的Ping、Pong幀來對連接進行保活或者驗證WebSocket連接是否可用。
如果您的業務需要設置超過函數計算能夠提供的最大請求超時時間,或者您的應用期望在運行期間保持邏輯上的連接穩定,您可以在客戶端代碼中加上超時重連機制。您可以借助Reconnecting-WebSocket的庫或SocketIO庫來實現該機制。
關于粘性會話(會話親和性)
函數計算是無狀態的,當函數的并發請求度較大的時候,函數計算無法保證來自同一客戶端的多個請求會被同一個容器處理。您可能需要通過外部存儲(Redis、Memcached、Kafka、數據庫等)來維持WebSocket請求在多個容器實例之間的狀態。
例如,對于聊天室應用,函數計算無法保證所有的用戶同時連接到同一個函數實例上。所以用戶的函數可以借助Redis的發布訂閱功能來實現聊天室,用戶加入一個聊天室的時候,會訂閱(Sub)該聊天室所在的頻道,當用戶1發送信息的時候,函數收到該消息,將其發布(Pub)到Redis中聊天室所在的頻道,因為在相同的聊天室的用戶均已經訂閱(Sub)了該聊天室的頻道,所以該聊天室的所有用戶都會收到用戶1剛才發送的消息。
計費方式
使用WebSocket的計費方式與使用HTTP的計費方式完全一致,您可以將WebSocket看作連接時間較長的HTTP調用。關于計費的更多信息,請參見計費概述。
對于并發度設置為1的函數,計費時間從WebSocket連接建立開始到WebSocket連接斷開結束。
對于并發度大于1的函數,實例的計費時間從收到第一個WebSocket連接建立開始,到最后一個WebSocket連接斷開結束。一個實例中多個連接同時存在期間,不會被重復計費。
如下圖所示,一個函數的并發度設置為2,第一個請求到達的時間為T1,結束時間為T3,第二個請求到達時間為T2,結束時間為T4,計費時間為T4-T1,其中T2到T3這段時間只會被計費一次,不會被重復計費。
更多示例
Custom Runtime | Custom Container |
常見問題
如果是您新創建的觸發器,會有10s左右的緩存更新時間,請稍后再試。
請檢查函數代碼中的依賴包是否正確安裝,更多信息,請參見為函數安裝第三方依賴。
請檢查函數監聽的端口和IP地址是否正確。監聽的IP地址可以是
0.0.0.0
,不能是127.0.0.1
或localhost
。如果您沒有配置自定義監聽端口,默認使用9000
端口。
WebSocket握手完成之前發生的錯誤主要分為以下兩種:
請求錯誤是指發送的Request不符合標準,在Response里報錯狀態碼為4xx。
函數錯誤,即編寫的函數有問題,會報5xx狀態碼。
錯誤類型 | X-Fc-Error-Type | HTTP狀態碼 | 原因分析 | 是否計費 |
請求錯誤 | FcCommonError | 400 | 您的請求超過Request限制項的限制。更多信息,請參見HTTP觸發器概述。 | 否 |
FcCommonError | 400 | 調用需要身份認證的函數的Request沒有傳入Date信息或Authorization信息。 | 否 | |
FcCommonError | 403 | 調用需要身份認證的函數的Request的簽名錯誤,即Authorization不正確。由于Date參與簽名計算,且超過15 min,簽名失效,一種常見的原因是使用需要訪問認證的HTTP觸發器,Request header中發送的Date據當前時間超過15 min,導致簽名失效。 | 否 | |
FcCommonError | 403 | 您的Request請求使用了HTTP觸發器中未配置的請求方法。WebSocket函數要求HTTP觸發器必須支持GET方法,如果沒有配置該方法,會報該錯誤 | 否 | |
FcCommonError | 404 | 向沒有設置HTTP觸發器的函數發送WebSocket請求。 | 否 | |
用戶流控 | FcCommonError | 429 | 用戶被流控,可減小并發量或者聯系阿里云函數計算團隊提高并發度。 | 否 |
系統錯誤 | FcCommonError | 500 | 函數計算系統錯誤,可重試解決。 | 否 |
系統流控 | FcCommonError | 503 | 函數計算系統流控。可用指數退避方式重試。 | 否 |
WebSocket握手完成之后的錯誤,均為函數代碼產生或引起的錯誤,您可以仔細檢查您的代碼,或者查看代碼運行中產生的日志。更多信息,請參見查看調用日志。
相關文檔
WebSocket協議在Runtime支持、超時時間、數據傳輸等方面有使用限制,請參見WebSocket協議使用限制。
HTTP觸發器支持同步調用和異步調用,具體使用請參見調用方式。
函數計算允許HTTP函數的調用請求跨域訪問,對跨域請求的處理方式請參見CORS請求處理。