Angular WebSocket代码详解
WebsocketService代码
import { Injectable } from '@angular/core';
import * as Rx from "rxjs/Rx";
@Injectable({
providedIn: 'root'
})
export class WebsocketService {
constructor() { }
private subject: Rx.Subject<MessageEvent>;
public connect(url): Rx.Subject<MessageEvent> {
if (!this.subject) {
this.subject = this.create(url);
console.log("Successfully connected: " + url);
}
return this.subject;
}
private create(url): Rx.Subject<MessageEvent> {
let ws = new WebSocket(url);
let observable = Rx.Observable.create((obs: Rx.Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = obs.complete.bind(obs);
return ws.close.bind(ws);
});
let observer = {
next: (data: string) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(data);
}
}
};
const innerSubject = new Rx.Subject();//为了能够多次订阅,用subject对observable进行封装
observable.subscribe(data => {
innerSubject.next(data)
});
return Rx.Subject.create(observer, innerSubject);
}
}
解释
使用Rxjs的Websocket库能让你在多个地方接收或发送消息:
- ws.onmessage = obs.next.bind(obs); 该句的意思是,当接收websocket发送的消息时,调用observer对象的next方法。用bind保证对象的this指针始终为observer对象。
- return Rx.Subject.create(observer, innerSubject);这句返回的是一个Subject对象,因为web socket的onmessage的参数是一个MessageEvent对象,所以这句返回的是Subject. 当外部订阅该返回对象后,在接收到websocket的onmessage消息后,observable 的next函数将发送onmessage函数的传入值,订阅对象就可以接收到。
- 为什么用innerSubject 对observable进行封装,因为observable只能订阅一次,而subject可以订阅多次,这样我们可以在不同的地方订阅,都可以接收到websocket消息。
ChatService代码
import { Injectable } from '@angular/core';
import { Subject } from "rxjs/Rx";
import { WebsocketService } from "./websocket.service";
import { AuthService } from 'src/app/core/auth.service';
const CHAT_URL = "ws://localhost:5000/ws/";
@Injectable({
providedIn: 'root'
})
export class ChatService {
public messages: Subject<string>;
constructor(wsService: WebsocketService, authService:AuthService) {
let authHeader = authService.getAuthorizationHeader() || "?";
var url = CHAT_URL + "?token=" + authHeader;
this.messages = <Subject<string>>wsService.connect(url).map(
(response: MessageEvent): string => {
console.log(response.data);
return response.data;
}
);
}
subscribeMessage() {
this.messages.subscribe(msg => {
console.log("Response from websocket: " + msg);
});
}
sendMessage(message) {
this.messages.next(message);
}
}
解释
- messages: Subject,我们用web socket发送接收Json字符串,所以这里的Subject的泛型对象是字符串。
- this.messages = <Subject>wsService.connect(url).map(
(response: MessageEvent): string => {.这里web socket的onmessage返回的是MessageEvent对象,这里用map函数吧Subject转换成为Subject.即我们的msaages对象。 - subscribeMessage() .当web socket的onmessage方法被调用后,websocketService中的Subject对象的next方法将发射MessageEvent对象,经过map转换后成为字符串对象,这里就是订阅到这个字符串。
- sendMessage(message),这里messages对象发送next消息就是调用WebsocketService中的observer的next,即next: (data: string) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(data); } }
先判断ws是否是打开状态,然后发送数据到服务器端。
调用
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ChatService } from '../service/chat.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor(private router: Router,
private chatService: ChatService) {
};
ngOnInit() {
this.chatService.subscribeMessage();//多个调用将接收多次。
}
sendMsg() {
this.chatService.sendMessage("test");
}
}