<1>web服务器
1、使用node.js创建服务器
node.js可以用typescript语言来开发;
node.js在使用http和socket方面做了大量的工作,可以减少我们自己的开发工作量。
1.新建一个文件夹serve,并用npm初始化这个文件夹
npm init -y
建立了一个包含默认配置的package.json文件
2.使用typescript语言开发,引入node的类型定义文件
npm i @types/node --save
类型定义文件的作用是可以让typescript可以使用现在已有的javascript的库
3.serve文件夹下新建配置文件tsconfig.json
node本身不认typescript,所以需要将typescript编译成javascript。
{
"compileOnSave": true,
"compilerOptions":{ //编译器配置
"target":"es5", //目标是编译成es5规范的脚本,也就是js
"module":"commonjs", //模块的规范是commonjs
"emitDecoratorMetadata": true,
"experimentalDecorators":true, //这两个是要保留装饰器的元数据
"outDir":"build", //编译后文件默认放置在build文件夹下
"lib":["es6"] //开发时使用es6的语法
},
"exclude": [ //编译时要排除的文件
"node_modules"
]
}
4.serve文件夹下新建文件serve\hello_serve.ts
import * as http from 'http';
const serve = http.createServer((request,response) => {
response.end("hello node!");
});
serve.listen(8000);
5.vs code编译器下
用Ctrl+Shift+B命令编译ts文件
6.用hello_serve.js文件启动node服务器
node build/hello_serve.js
7.浏览器中访问http://localhost:8000/
得到服务器返回的字符串
2、使用Epress创建restful的http服务
Epress框架提供了所以web应用都需要的一些常用功能
1.安装Epress框架
npm install express --save
2.安装Epress框架类型定义文件来进行typescript开发
npm install @types/express --save
3.在serve/serve目录下新建配置文件action_serve.ts
import * as express from 'express';
const app = express();
// 当服务器为开启状态时,如果在根目录'/'下,
// 接收到了get请求,那么服务器会返回hello express
app.get('/',(req, res) => {
res.send("hello express");
});
app.get('/product',(req,res) => {
res.send("接收到产品查询请求");
});
const serve = app.listen(8000,"localhost",() => {
console.log("服务器已启动,地址为http://localhose:8000");
});
4.vs code编译器下
用Ctrl+Shift+B命令编译ts文件
5.用auction_serve.js文件启动node服务器
node build/auction_serve.js
控制台中
6.浏览器中访问http://localhost:8000/
访问product时
此时已经建立好了两个http服务
3、监控服务器文件的变化
因为当修改文件时,重新刷新地址,内容是不会变化的,必须要重启服务才可以更新内容,所以下面安装可以监控源代码变化并自动重启服务器的工具nodemonitor。
1.安装nodemon
···
npm install -g nodemon
···
2.用nodemon来启动服务器
nodemon build/auction_serve.js
当修改内容时
4、修改产品查询请求的服务
产品查询请求的服务应该返回一个json数据
1.修改auction_serve.ts
import * as express from 'express';
const app = express();
// 商品类的定义文件
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public rating:number,
public desc:string
){}
}
// 商品数据
const products:Product[] = [
new Product(1,"商品1",1.99,1.5,"这是商品1"),
new Product(2,"商品2",2.99,2.5,"这是商品2"),
new Product(3,"商品3",3.99,3.5,"这是商品3"),
new Product(4,"商品4",4.99,4.5,"这是商品4"),
new Product(5,"商品5",5.99,4.5,"这是商品5")
];
app.get('/',(req, res) => {
res.send("hello express");
});
//此时返回的是一个json数据,传入定义的products
app.get('/product',(req,res) => {
res.json(products);
});
const serve = app.listen(8000,"localhost",() => {
console.log("服务器已启动,地址为http://localhose:8000");
});
2.刷新浏览器
5、新增服务,可以根据指定的id来获取商品信息
1.修改auction_serve.ts
import * as express from 'express';
const app = express();
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public rating:number,
public desc:string
){}
}
const products:Product[] = [
new Product(1,"商品1",1.99,1.5,"这是商品1"),
new Product(2,"商品2",2.99,2.5,"这是商品2"),
new Product(3,"商品3",3.99,3.5,"这是商品3"),
new Product(4,"商品4",4.99,4.5,"这是商品4"),
new Product(5,"商品5",5.99,4.5,"这是商品5")
];
app.get('/',(req, res) => {
res.send("hello express");
});
app.get('/product',(req,res) => {
res.json(products);
});
// 新增根据id查询数据的服务
app.get('/product/:id',(req,res) => {
res.json(products.find((product) => product.id == req.params.id));
});
const serve = app.listen(8000,"localhost",() => {
console.log("服务器已启动,地址为http://localhose:8000");
});
2.结果
<2>http通信
在angular应用中发送http请求来调用上面新建的服务,并处理服务器返回的数据。
在默认情况下,angular的http服务使用响应式编程的方式来处理http请求。
1.在angular项目中新建一个产品组件
ng g component product
2.修改app.module.ts,引入HttpModule模块
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ProductComponent } from './product/product.component';
// 引入
import { HttpModule } from '@angular/http';
@NgModule({
declarations: [
AppComponent,
ProductComponent
],
imports: [
BrowserModule,
// 引入
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
3.修改product.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Http } from '@angular/http';
import 'rxjs/Rx';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
// 声明一个流,负责接收服务器上传过来的流
dataSource:Observable;
// 用来和模版做数据绑定的数组
myproducts:Array = [];
// 将angular的服务依赖注入进来
constructor(private http:Http) {
this.dataSource = this.http.get('/product')
.map((res) => res.json());
}
ngOnInit() {
// 订阅流
this.dataSource.subscribe(
// 把订阅到的数据传给myproducts属性
(data) => this.myproducts = data
)
}
}
http发get请求,返回response,拿到response里的json数据赋值给myproducts
因为此时获取产品信息的路径为http://localhost:4200/product,而服务器的地址为http://localhost:8000/product,所以还要进行配置。
4.根目录下新建一个配置文件proxy.conf.json
将前缀为api的路径转发到http://localhost:8000上
{
"/api": {
"target": "http://localhost:8000"
}
}
5.修改package.json
6.修改serve文件下的auction_serve.ts
7.用下面的命令重启angular项目
ng serve --proxy-config proxy.conf.json
8.结果
方法二
在模版上使用异步管道async自动的订阅流
1.修改模版
商品信息
-
{{pro.title}}
2.修改控制器
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Http } from '@angular/http';
import 'rxjs/Rx';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
// 流直接给myproducts
myproducts:Observable;
constructor(private http:Http) {
this.myproducts = this.http.get('/api/product')
.map((res) => res.json());
}
ngOnInit() {
// 删除订阅
}
}
3.结果相同
<3>websocket通讯
1、了解websocket协议
websocket是一种低负载的二进制协议。
2、创建websocket服务器
1.在serve中安装ws依赖库和类型文件
npm install ws --save
npm install @types/ws --save-dev
2.修改auction_serve.ts
import * as express from 'express';
// 引入服务
import {Server} from 'ws';
const app = express();
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public rating:number,
public desc:string
){}
}
const products:Product[] = [
new Product(1,"商品1",1.99,1.5,"这是商品1"),
new Product(2,"商品2",2.99,2.5,"这是商品2"),
new Product(3,"商品3",3.99,3.5,"这是商品3"),
new Product(4,"商品4",4.99,4.5,"这是商品4"),
new Product(5,"商品5",5.99,4.5,"这是商品5")
];
app.get('/',(req, res) => {
res.send("hello express");
});
app.get('/api/product',(req,res) => {
res.json(products);
});
app.get('/api/product/:id',(req,res) => {
res.json(
products.find((product) => product.id == req.params.id)
);
});
const serve = app.listen(8000,"localhost",() => {
console.log("服务器已启动,地址为http://localhose:8000");
});
// 新建一个webscoket服务
const wsServer = new Server({port:8085});
wsServer.on("connection",websocket => {
websocket.send("这个消息是服务器主动推送的");
});
3.写客户端的服务,在angular项目中生成一个服务service
ng g service shared/webSocket
出现问题:Error: ELOOP: too many symbolic links encountered
解决办法:删除node_modules文件夹, 重新npm install
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable()
export class WebSocketService {
// 客户端的服务
ws:WebSocket;
constructor() { }
// 定义返回一个流,这个流包含了服务器返回的消息
creatObservableSocket(url:string) :Observable {
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();
}
)
}
// 向服务器发送一个消息
sendMess(message:string) {
this.ws.send(message);
}
}
4.客户端的组件,新建一个组件
ng g component webSocketComponent
1.修改web-socket-component.component.ts
import { Component, OnInit } from '@angular/core';
import { WebSocketService } from './../shared/web-socket.service';
@Component({
selector: 'app-web-socket-component',
templateUrl: './web-socket-component.component.html',
styleUrls: ['./web-socket-component.component.css']
})
export class WebSocketComponentComponent implements OnInit {
// 将刚刚写的客户端的服务WebSocketService通过依赖注入,注入到组件中来
constructor(private wsService:WebSocketService) { }
ngOnInit() {
// 订阅服务器发来消息产生的流
this.wsService.creatObservableSocket("ws://localhost:8085")
.subscribe(
data => console.log(data),
err => console.log(err),
() => console.log("流已经结束")
)
}
// 向服务器主动发送消息
sendMessagegToServer(){
this.wsService.sendMess("这是客户端发过来的消息");
}
}
2.修改模版
3.修改app.module.ts -- sproviders里使用提供器
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ProductComponent } from './product/product.component';
import { HttpModule } from '@angular/http';
import { WsComponentComponent } from './ws-component/ws-component.component';
import { WebSocketComponentComponent } from './web-socket-component/web-socket-component.component';
// 引入
import { WebSocketService } from './shared/web-socket.service';
@NgModule({
declarations: [
AppComponent,
ProductComponent,
WsComponentComponent,
WebSocketComponentComponent
],
imports: [
BrowserModule,
HttpModule
],
//使用依赖注入时,要在providers里使用提供器
providers: [WebSocketService],
bootstrap: [AppComponent]
})
export class AppModule { }
4.修改serve中auction_serve.ts
import * as express from 'express';
import {Server} from 'ws';
const app = express();
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public rating:number,
public desc:string
){}
}
const products:Product[] = [
new Product(1,"商品1",1.99,1.5,"这是商品1"),
new Product(2,"商品2",2.99,2.5,"这是商品2"),
new Product(3,"商品3",3.99,3.5,"这是商品3"),
new Product(4,"商品4",4.99,4.5,"这是商品4"),
new Product(5,"商品5",5.99,4.5,"这是商品5")
];
app.get('/',(req, res) => {
res.send("hello express");
});
app.get('/api/product',(req,res) => {
res.json(products);
});
app.get('/api/product/:id',(req,res) => {
res.json(
products.find((product) => product.id == req.params.id)
);
});
const serve = app.listen(8000,"localhost",() => {
console.log("服务器已启动,地址为http://localhose:8000");
});
// 新建一个服务
const wsServer = new Server({port:8085});
wsServer.on("connection",websocket => {
websocket.send("这个消息是服务器主动推送的");
websocket.on("message",message => {
console.log("message"+message);
});
});
5.结果
5.定时推送
修改auction_serve.ts
setInterval(()=>{
// 判断客户端是连接上的状态
if(wsServer.clients) {
wsServer.clients.forEach(client => {
client.send("这是定时推送");
})
}
},2000);