WeSocket通讯
- WeSocket协议:低负载二进制协议,允许在同一个连接中同时双方向的数据传递,在发送请求的同时还能接受数据,所以WeSocket协议通讯时延迟低,而且由于常连接的存在,不需要每次请求时都需要携带一些连接相关的信息
http协议进行通讯时,客户端和服务器的连接在同一时间只能有一个发送请求和服务器响应不能同时进行 - 安装WeSocket依赖库和类型定义文件
npm i ws --save
npm i @types/ws --save-dev
- 在8085端口创建一个服务器,当有客户端连接到这个服务器时给这个客户端推送一个消息
import {Server} from 'ws'
const wsServer =new Server({port:8085});
wsServer.on("connection",websocket=>{
websocket.send("服务器主动推送消息");
websocket.on("message",message=>{
console.log("接收"+message);
})
});
- 在需要连接的客户端中生成一个service
ng g service shared/webSocket
export class WebSocketService {
ws:WebSocket;
constructor() { }
createObservableSocket(url:string):Observable<any>{
this.ws=new WebSocket(url);
return new Observable(
observer=>{
this.ws.onmessage=(event)=>observer.next(event.data);
this.ws.onerror=(event)=>observer.error(event);
this.ws.onclose=(event)=>observer.complete();
}
);
}
sendMessage(message:string){
this.ws.send(message);
}
}
export class WebSocketComponent implements OnInit {
constructor(private wsService:WebSocketService) { }
ngOnInit() {
this.wsService.createObservableSocket("ws://localhost:8085")
.subscribe(
data=>console.log(data),
err=>console.log(err),
()=>console.log("流已经结束")
);
}
sendMessageToserver(){
this.wsService.sendMessage("hello from client");
}
}
- 定时向所有客户端推送消息
setInterval(()=>{
if(wsServer.clients){
wsServer.clients.forEach(client=>{
client.send("定时推送");
})
}
},2000);
从服务器将数据传输到客户端使用
- 将商品服务中的商品数组和评论数组放入到node服务器中,从服务器中获取数据,将方法中的商品数组,和评论数组使用一个流Observable来引用
getProducts(): Observable<Product[]> {
return this.http.get("/api/products").map(res=>res.json());
}
getProduct(id:number): Observable<Product> {
return this.http.get("/api/product"+id).map(res=>res.json());
}
getCommentsForProductId(id: number):Observable<Comment[]> {
return this.http.get("/api/product"+id+"/comments").map(res=>res.json());
}
- 在商品组件中同样执行相同的操作使用Observable,并且在模板中将管道过滤器改为使用异步管道async
<div class="col-md-4 col-sm-4 col-lg-4" *ngFor="let product of products | async">
- 在商品详情组件中将服务器获取的两个数组的流转化成数组以便使用
ngOnInit() {
let productId:number = this.routeInfo.snapshot.params["productId"];
this.productService.getProduct(productId).subscribe(
product=>this.product=product
);
this.productService.getCommentsForProductId(productId).subscribe(
comments=>this.comments=comments
)
}
- 在界面中有属性不能读取,说明有数据属于undefined,因为现在的服务都是通过http,这就是一个异步服务,在组件中还没有获取到数据时就属于undefined需要将模板中的product和comment后加上?,但是for循环中的comment不需要更改,因为ngFor是会自动检测数据是否为空,这样就完成了数据从服务器到客户端的传输
<div class="thumbnail">
<img src="http://placehold.it/820x230" >
<div>
<h4 class="pull-right">{{product?.price}}元</h4>
<h4>{{product?.title}}</h4>
<p>{{product?.desc}}</p>
</div>
<div>
<p class="pull-right">评论 {{comments?.length}} 条</p>
<p>
<app-start [rating]="product?.rating" ></app-start>
</p>
</div>
</div>
<div class="well">
<div>
<button class="btn btn-success" (click)="isCommentHidden=!isCommentHidden">评论</button>
</div>
<div [hidden]="isCommentHidden">
<div><app-start [(rating)]="newRating" [readonly]="false"></app-start></div>
<div>
<textarea [(ngModel)]="newComment"></textarea>
</div>
<button class="btn" (click)="addComment()">发表</button>
</div>
<div class="row" *ngFor="let comment of comments">
<hr>
<div>
<div class="col-md-12">
<app-start [rating]="comment?.rating"></app-start>
<span>用户名:{{comment.user}}</span>
<span class="pull-right">{{comment.timestamp}}</span>
<p></p>
<p>
{{comment.content}}
</p>
</div>
</div>
</div>
</div>