教學課程:使用子通訊協定在 WebSocket 用戶端之間發佈和訂閱訊息
在建置聊天應用程式教學課程中,您已了解如何使用 WebSocket API 搭配 Azure Web PubSub 傳送和接收資料。 您可以看到,用戶端與服務通訊時不需要通訊協定。 例如,您可以使用 WebSocket.send()
傳送任何類型的資料,然後伺服器會按照原狀接收資料。 WebSocket API 流程易於使用,但功能有限。 例如,您無法在將事件傳送至伺服器時指定事件名稱,或將訊息發佈至其他用戶端,而不是將它傳送至您的伺服器。 在本教學課程中,您會了解如何使用子通訊協定來擴充用戶端的功能。
在本教學課程中,您會了解如何:
- 建立 Web PubSub 服務執行個體
- 產生建立 WebSocket 連線的完整 URL
- 使用子通訊協定在 WebSocket 用戶端之間發佈訊息
如果您沒有 Azure 訂閱,請在開始之前,先建立 Azure 免費帳戶。
必要條件
- 此設定需要 2.22.0 版或更新版本的 Azure CLI。 如果您是使用 Azure Cloud Shell,就已安裝最新版本。
建立 Azure Web PubSub 執行個體
建立資源群組
資源群組是在其中部署與管理 Azure 資源的邏輯容器。 使用 az group create 命令,在 eastus
位置中建立名為 myResourceGroup
的資源群組。
az group create --name myResourceGroup --location EastUS
建立 Web PubSub 執行個體
執行 az extension add 以安裝 webpubsub 延伸模組,或將該延伸模組升級至目前版本。
az extension add --upgrade --name webpubsub
使用 Azure CLI az webpubsub create 命令,在您已建立的資源群組中建立 Web PubSub。 下列命令會在 EastUS 的資源群組 myResourceGroup 下建立免費 Web PubSub 資源:
重要
每個 Web PubSub 資源都必須有唯一的名稱。 使用下列範例中的 Web PubSub 名稱取代 <your-unique-resource-name>。
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
此命令的輸出顯示新建資源的屬性。 請記下下列兩個屬性:
- 資源名稱:您提供給上述
--name
參數的名稱。
- hostName:在此範例中,主機名稱為
<your-unique-resource-name>.webpubsub.azure.com/
。
此時,您的 Azure 帳戶是唯一獲得授權在此新資源上執行任何作業的帳戶。
取得 ConnectionString 以供後續使用
重要
連接字串包含應用程式存取 Azure Web PubSub 服務所需的授權資訊。 連接字串內的存取金鑰類似於服務的根密碼。 在實際執行環境中,請務必小心保護您的存取金鑰。 使用 Azure Key Vault,以安全的方式管理及輪替金鑰。 避免將存取金鑰散發給其他使用者、寫入程式碼,或將其以純文字儲存在他人可以存取的位置。 如果您認為金鑰可能已遭盜用,請輪替金鑰。
使用 Azure CLI az webpubsub key 命令取得服務的 ConnectionString。 使用您的 Azure Web PubSub 執行個體名稱取代 <your-unique-resource-name>
預留位置。
az webpubsub key show --resource-group myResourceGroup --name <your-unique-resource-name> --query primaryConnectionString --output tsv
複製連接字串以供後續使用。
複製擷取的 ConnectionString,以稍後在本教學課程中用來做為 <connection_string>
的值。
設定專案
必要條件
使用子通訊協定
用戶端可以使用特定的子通訊協定來啟動 WebSocket 連線。 Azure Web PubSub 服務支援名為 json.webpubsub.azure.v1
的子通訊協定,可讓用戶端直接透過 Web PubSub 服務發佈/訂閱,而不是往返上游伺服器。 如需有關子通訊協定的詳細資訊,請參閱 Azure Web PubSub 支援的 JSON WebSocket 子通訊協定 (部分機器翻譯)。
如果您使用其他通訊協定名稱,服務會忽略它們並在連線事件處理常式中傳遞至伺服器,讓您可以建置自己的通訊協定。
現在,讓我們使用 json.webpubsub.azure.v1
子通訊協定建立 Web 應用程式。
安裝相依性
mkdir logstream
cd logstream
dotnet new web
dotnet add package Microsoft.Extensions.Azure
dotnet add package Azure.Messaging.WebPubSub
mkdir logstream
cd logstream
npm init -y
npm install --save express
npm install --save ws
npm install --save node-fetch
npm install --save @azure/web-pubsub
mkdir logstream
cd logstream
# Create venv
python -m venv env
# Active venv
source ./env/bin/activate
pip install azure-messaging-webpubsubservice
您會使用 Javalin Web 架構來裝載網頁。
首先,讓我們使用 Maven 建立新的應用程式 logstream-webserver
,並切換至 logstream-webserver 資料夾:
mvn archetype:generate --define interactiveMode=n --define groupId=com.webpubsub.tutorial --define artifactId=logstream-webserver --define archetypeArtifactId=maven-archetype-quickstart --define archetypeVersion=1.4
cd logstream-webserver
讓我們將 Azure Web PubSub SDK 和 javalin
Web 架構相依性新增至 pom.xml
的 dependencies
節點:
javalin
:適用於 JAVA 的簡單 Web 架構
slf4j-simple
:適用於 JAVA 的記錄器
azure-messaging-webpubsub
:使用 Azure Web PubSub 的服務用戶端 SDK
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-webpubsub</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.javalin/javalin -->
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>3.13.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
建立伺服器端來裝載 /negotiate
API 和網頁。
使用下列程式碼更新 Program.cs
。
- 使用
AddAzureClients
新增服務用戶端,並從設定中讀取連接字串。
- 在
app.Run();
前面加上 app.UseStaticFiles();
以支援靜態檔案。
- 然後更新
app.MapGet
,以產生具有 /negotiate
要求的用戶端存取權杖。
using Azure.Messaging.WebPubSub;
using Microsoft.Extensions.Azure;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureClients(s =>
{
s.AddWebPubSubServiceClient(builder.Configuration["Azure:WebPubSub:ConnectionString"], "stream");
});
var app = builder.Build();
app.UseStaticFiles();
app.MapGet("/negotiate", async context =>
{
var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>();
var response = new
{
url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri
};
await context.Response.WriteAsJsonAsync(response);
});
app.Run();
建立 server.js
並新增下列程式碼:
const express = require('express');
const { WebPubSubServiceClient } = require('@azure/web-pubsub');
let service = new WebPubSubServiceClient(process.env.WebPubSubConnectionString, 'stream');
const app = express();
app.get('/negotiate', async (req, res) => {
let token = await service.getClientAccessToken({
roles: ['webpubsub.sendToGroup.stream', 'webpubsub.joinLeaveGroup.stream']
});
res.send({
url: token.url
});
});
app.use(express.static('public'));
app.listen(8080, () => console.log('server started'));
建立 server.py
來裝載 /negotiate
API 和網頁。
import json
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler
from azure.messaging.webpubsubservice import WebPubSubServiceClient
service = WebPubSubServiceClient.from_connection_string(sys.argv[1], hub='stream')
class Resquest(SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.path = 'public/index.html'
return SimpleHTTPRequestHandler.do_GET(self)
elif self.path == '/negotiate':
roles = ['webpubsub.sendToGroup.stream',
'webpubsub.joinLeaveGroup.stream']
token = service.get_client_access_token(roles=roles)
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({
'url': token['url']
}).encode())
if __name__ == '__main__':
if len(sys.argv) != 2:
print('Usage: python server.py <connection-string>')
exit(1)
server = HTTPServer(('localhost', 8080), Resquest)
print('server started')
server.serve_forever()
讓我們瀏覽至 /src/main/java/com/webpubsub/tutorial 目錄、在您的編輯器中開啟 App.java 檔案,使用 Javalin.create
提供靜態檔案:
package com.webpubsub.tutorial;
import com.azure.messaging.webpubsub.WebPubSubServiceClient;
import com.azure.messaging.webpubsub.WebPubSubServiceClientBuilder;
import com.azure.messaging.webpubsub.models.GetClientAccessTokenOptions;
import com.azure.messaging.webpubsub.models.WebPubSubClientAccessToken;
import io.javalin.Javalin;
public class App {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Expecting 1 arguments: <connection-string>");
return;
}
// create the service client
WebPubSubServiceClient service = new WebPubSubServiceClientBuilder()
.connectionString(args[0])
.hub("chat")
.buildClient();
// start a server
Javalin app = Javalin.create(config -> {
config.addStaticFiles("public");
}).start(8080);
// Handle the negotiate request and return the token to the client
app.get("/negotiate", ctx -> {
GetClientAccessTokenOptions option = new GetClientAccessTokenOptions();
option.addRole("webpubsub.sendToGroup.stream");
option.addRole("webpubsub.joinLeaveGroup.stream");
WebPubSubClientAccessToken token = service.getClientAccessToken(option);
// return JSON string
ctx.result("{\"url\":\"" + token.getUrl() + "\"}");
return;
});
}
}
視您的設定而定,您可能需要在 pom.xml 中明確將程式設計語言層級設定為 JAVA 8。 新增下列程式碼片段:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
建立網頁
使用下列內容建立 HTML 頁面,並將其儲存為 wwwroot/index.html
:
使用下列內容建立 HTML 頁面,並將其儲存為 public/index.html
:
使用下列內容建立 HTML 頁面,並將其儲存為 public/index.html
:
使用下列內容建立 HTML 頁面,並將其儲存至 /src/main/resources/public/index.html:
<html>
<body>
<div id="output"></div>
<script>
(async function () {
let res = await fetch('/negotiate')
let data = await res.json();
let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
ws.onopen = () => {
console.log('connected');
};
let output = document.querySelector('#output');
ws.onmessage = event => {
let d = document.createElement('p');
d.innerText = event.data;
output.appendChild(d);
};
})();
</script>
</body>
</html>
上述程式碼會連線至服務,並將收到的任何訊息列印至頁面。 主要的變更是我們在建立 WebSocket 連線時指定子通訊協定。
執行伺服器
我們使用適用於 .NET Core 的 Secret Manager 工具來設定連接字串。 執行下列命令,使用在前一個步驟中擷取的命令取代 <connection_string>
,並在瀏覽器中開啟 http://localhost:5000/index.html:
dotnet user-secrets init
dotnet user-secrets set Azure:WebPubSub:ConnectionString "<connection-string>"
dotnet run
現在執行下列命令,使用在前一個步驟中擷取的 ConnectionString 取代 <connection-string>
,並在瀏覽器中開啟 http://localhost:8080:
export WebPubSubConnectionString="<connection-string>"
node server
現在執行下列命令,使用在前一個步驟中擷取的 ConnectionString 取代 <connection-string>
,並在瀏覽器中開啟 http://localhost:8080:
python server.py "<connection-string>"
現在執行下列命令,使用在前一個步驟中擷取的 ConnectionString 取代 <connection-string>
,並在瀏覽器中開啟 http://localhost:8080:
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.tutorial.App" -Dexec.cleanupDaemonThreads=false -Dexec.args="'<connection_string>'"
如果您使用 Chrome,您可以按 F12 或以滑鼠右鍵按一下 -> [檢查] -> [開發人員工具],然後選取 [網路] 索引標籤。載入網頁,您可以看到 WebSocket 連線已建立。 選取以檢查 WebSocket 連線,您可以看到用戶端中已收到下列 connected
事件訊息。 您可以看到您可以取得針對此用戶端產生的 connectionId
。
{"type":"system","event":"connected","userId":null,"connectionId":"<the_connection_id>"}
您可以看到,透過在子通訊協定的協助,您可以在連線為 connected
時取得連線的一些中繼資料。
用戶端現在會收到 JSON 訊息,而不是純文字。 JSON 訊息包含更多詳細資訊,例如訊息的類型和來源。 因此,您可以使用此資訊對訊息進行更多處理 (例如,如果訊息來自不同的來源,則以不同的樣式顯示訊息),您可以在後面的區段中找到。
從用戶端發佈訊息
在建置聊天應用程式教學課程中,當用戶端透過 WebSocket 連線傳送訊息至 Web PubSub 服務時,服務會在伺服器端觸發使用者事件。 使用子通訊協定時,用戶端會藉由傳送 JSON 訊息擁有更多功能。 例如,您可以透過 Web PubSub 服務直接從用戶端將訊息發佈至其他用戶端。
如果您想要將大量資料即時串流至其他用戶端,這會很有用。 讓我們使用此功能建置記錄串流應用程式,將主控台記錄即時串流至瀏覽器。
建立串流程式
建立 stream
程式:
mkdir stream
cd stream
dotnet new console
使用下列內容更新 Program.cs
:
using System;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace stream
{
class Program
{
private static readonly HttpClient http = new HttpClient();
static async Task Main(string[] args)
{
// Get client url from remote
var stream = await http.GetStreamAsync("http://localhost:5000/negotiate");
var url = (await JsonSerializer.DeserializeAsync<ClientToken>(stream)).url;
var client = new ClientWebSocket();
client.Options.AddSubProtocol("json.webpubsub.azure.v1");
await client.ConnectAsync(new Uri(url), default);
Console.WriteLine("Connected.");
var streaming = Console.ReadLine();
while (streaming != null)
{
if (!string.IsNullOrEmpty(streaming))
{
var message = JsonSerializer.Serialize(new
{
type = "sendToGroup",
group = "stream",
data = streaming + Environment.NewLine,
});
Console.WriteLine("Sending " + message);
await client.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, default);
}
streaming = Console.ReadLine();
}
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
}
private sealed class ClientToken
{
public string url { get; set; }
}
}
}
使用下列內容建立 stream.js
。
const WebSocket = require('ws');
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
async function main() {
let res = await fetch(`http://localhost:8080/negotiate`);
let data = await res.json();
let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
let ackId = 0;
ws.on('open', () => {
process.stdin.on('data', data => {
ws.send(JSON.stringify({
type: 'sendToGroup',
group: 'stream',
ackId: ++ackId,
dataType: 'text',
data: data.toString()
}));
});
});
ws.on('message', data => console.log("Received: %s", data));
process.stdin.on('close', () => ws.close());
}
main();
上述程式碼會建立與服務的 WebSocket 連線,然後每當它收到某些資料時,就會使用 ws.send()
來發佈資料。 如果要發佈給其他人,您只需將 type
設定為 sendToGroup
並在訊息中指定群組名稱。
開啟 stream
程式的另一個 bash 視窗,並安裝 websockets
相依性:
mkdir stream
cd stream
# Create venv
python -m venv env
# Active venv
source ./env/bin/activate
pip install websockets
使用下列內容建立 stream.py
。
import asyncio
import sys
import threading
import time
import websockets
import requests
import json
async def connect(url):
async with websockets.connect(url, subprotocols=['json.webpubsub.azure.v1']) as ws:
print('connected')
id = 1
while True:
data = input()
payload = {
'type': 'sendToGroup',
'group': 'stream',
'dataType': 'text',
'data': str(data + '\n'),
'ackId': id
}
id = id + 1
await ws.send(json.dumps(payload))
await ws.recv()
if __name__ == '__main__':
res = requests.get('http://localhost:8080/negotiate').json()
try:
asyncio.get_event_loop().run_until_complete(connect(res['url']))
except KeyboardInterrupt:
pass
上述程式碼會建立與服務的 WebSocket 連線,然後每當它收到某些資料時,就會使用 ws.send()
來發佈資料。 如果要發佈給其他人,您只需將 type
設定為 sendToGroup
並在訊息中指定群組名稱。
讓我們使用另一個終端機,回到根資料夾來建立串流主控台應用程式 logstream-streaming
,並切換至 logstream-streaming 資料夾:
mvn archetype:generate --define interactiveMode=n --define groupId=com.webpubsub.quickstart --define artifactId=logstream-streaming --define archetypeArtifactId=maven-archetype-quickstart --define archetypeVersion=1.4
cd logstream-streaming
讓我們將 HttpClient 相依性新增至 pom.xml
的 dependencies
節點:
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
現在讓我們使用 WebSocket 來連線到服務。 讓我們瀏覽至 /src/main/java/com/webpubsub/quickstart 目錄、在編輯器中開啟 App.java 檔案,並將程式碼取代為:
package com.webpubsub.quickstart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import com.google.gson.Gson;
public class App
{
public static void main( String[] args ) throws IOException, InterruptedException
{
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080/negotiate"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Gson gson = new Gson();
String url = gson.fromJson(response.body(), Entity.class).url;
WebSocket ws = HttpClient.newHttpClient().newWebSocketBuilder().subprotocols("json.webpubsub.azure.v1")
.buildAsync(URI.create(url), new WebSocketClient()).join();
int id = 0;
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String streaming = reader.readLine();
App app = new App();
while (streaming != null && !streaming.isEmpty()){
String frame = gson.toJson(app.new GroupMessage(streaming + "\n", ++id));
System.out.println("Sending: " + frame);
ws.sendText(frame, true);
streaming = reader.readLine();
}
}
private class GroupMessage{
public String data;
public int ackId;
public final String type = "sendToGroup";
public final String group = "stream";
GroupMessage(String data, int ackId){
this.data = data;
this.ackId = ackId;
}
}
private static final class WebSocketClient implements WebSocket.Listener {
private WebSocketClient() {
}
@Override
public void onOpen(WebSocket webSocket) {
System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol());
WebSocket.Listener.super.onOpen(webSocket);
}
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("onText received " + data);
return WebSocket.Listener.super.onText(webSocket, data, last);
}
@Override
public void onError(WebSocket webSocket, Throwable error) {
System.out.println("Bad day! " + webSocket.toString());
WebSocket.Listener.super.onError(webSocket, error);
}
}
private static final class Entity {
public String url;
}
}
- 瀏覽至包含 pom.xml 檔案的目錄,然後使用下列命令執行專案
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.quickstart.App" -Dexec.cleanupDaemonThreads=false
您可以看到,這裡有個新的概念「群組」。 群組是中樞中的邏輯概念,您可以在其中將訊息發佈至連線群組。 在中樞中,您可以有多個群組,而一個用戶端可以同時訂閱多個群組。 使用子通訊協定時,您只能發佈至群組,而不是廣播至整個中樞。 如需有關字詞的詳細資訊,請參閱基本概念。
因為我們在這裡使用群組,所以在 ws.onopen
回呼內建立 WebSocket 連線時,我們也需要更新網頁 index.html
以加入群組。
let ackId = 0;
ws.onopen = () => {
console.log('connected');
ws.send(JSON.stringify({
type: 'joinGroup',
group: 'stream',
ackId: ++ackId
}));
};
您可以看到,用戶端透過傳送 joinGroup
類型的訊息來加入群組。
此外,請稍微更新 ws.onmessage
回呼邏輯,以剖析 JSON 回應,並僅列印來自 stream
群組的訊息,使其做為即時串流印表機。
ws.onmessage = event => {
let message = JSON.parse(event.data);
if (message.type === 'message' && message.group === 'stream') {
let d = document.createElement('span');
d.innerText = message.data;
output.appendChild(d);
window.scrollTo(0, document.body.scrollHeight);
}
};
基於安全性考慮,用戶端預設無法自行發佈或訂閱群組。 因此,您會注意到,我們在產生權杖時為用戶端設定 roles
:
當 GenerateClientAccessUri
在 Startup.cs
中時,設定 roles
,如下所示:
service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
當 getClientAccessToken
在 server.js
中時,新增 roles
,如下所示:
app.get('/negotiate', async (req, res) => {
let token = await service.getClientAccessToken({
roles: ['webpubsub.sendToGroup.stream', 'webpubsub.joinLeaveGroup.stream']
});
...
});
在產生存取權杖的流程中,在 server.py
中為用戶端設定正確的角色:
roles = ['webpubsub.sendToGroup.stream',
'webpubsub.joinLeaveGroup.stream']
token = service.get_client_access_token(roles=roles)
在產生存取權杖的流程中,在 App.java
中為用戶端設定正確的角色:
GetClientAccessTokenOptions option = new GetClientAccessTokenOptions();
option.addRole("webpubsub.sendToGroup.stream");
option.addRole("webpubsub.joinLeaveGroup.stream");
WebPubSubClientAccessToken token = service.getClientAccessToken(option);
最後,也套用一些樣式到 index.html
,使其妥善地顯示。
<html>
<head>
<style>
#output {
white-space: pre;
font-family: monospace;
}
</style>
</head>
現在,執行下列程式碼並輸入任何文字,這些文字會即時顯示在瀏覽器中:
ls -R | dotnet run
# Or call `dir /s /b | dotnet run` when you are using CMD under Windows
或者,您可以放慢速度,以便看到資料即時串流至瀏覽器:
for i in $(ls -R); do echo $i; sleep 0.1; done | dotnet run
您可以在這裡找到此教學課程的完整程式碼範例。
node stream
或者,您也可以使用此應用程式管道,從另一個主控台應用程式傳送任何輸出,並將其串流至瀏覽器。 例如:
ls -R | node stream
# Or call `dir /s /b | node stream` when you are using CMD under Windows
或者,您可以放慢速度,以便看到資料即時串流至瀏覽器:
for i in $(ls -R); do echo $i; sleep 0.1; done | node stream
您可以在這裡找到此教學課程的完整程式碼範例。
現在,執行 python stream.py
並輸入任何文字,這些文字會即時顯示在瀏覽器中。
或者,您也可以使用此應用程式管道,從另一個主控台應用程式傳送任何輸出,並將其串流至瀏覽器。 例如:
ls -R | python stream.py
# Or call `dir /s /b | python stream.py` when you are using CMD under Windows
或者,您可以放慢速度,以便看到資料即時串流至瀏覽器:
for i in $(ls -R); do echo $i; sleep 0.1; done | python stream.py
您可以在這裡找到此教學課程的完整程式碼範例。
現在,執行下列程式碼並輸入任何文字,這些文字會即時顯示在瀏覽器中。
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.quickstart.App" -Dexec.cleanupDaemonThreads=false
您可以在這裡找到此教學課程的完整程式碼範例。
下一步
此教學課程提供如何連線至 Web PubSub 服務,以及如何將訊息發佈至已連線用戶端的基本概念。
請查看其他教學課程,以進一步了解如何使用此服務。