美文网首页Angualr我爱编程
angular (6)与服务器通信

angular (6)与服务器通信

作者: mumumuu | 来源:发表于2018-06-25 15:41 被阅读124次

    <1>web服务器

    1、使用node.js创建服务器

    node.js可以用typescript语言来开发;
    node.js在使用http和socket方面做了大量的工作,可以减少我们自己的开发工作量。
    1.新建一个文件夹serve,并用npm初始化这个文件夹

    npm init -y
    

    建立了一个包含默认配置的package.json文件


    64.png

    2.使用typescript语言开发,引入node的类型定义文件

    npm i @types/node --save
    

    类型定义文件的作用是可以让typescript可以使用现在已有的javascript的库


    65.png

    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

    66.png
    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文件

    67.png

    6.用hello_serve.js文件启动node服务器

    node build/hello_serve.js
    

    7.浏览器中访问http://localhost:8000/
    得到服务器返回的字符串

    68.png

    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

    69.png
    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文件

    70.png

    5.用auction_serve.js文件启动node服务器

    node build/auction_serve.js
    

    控制台中


    71.png

    6.浏览器中访问http://localhost:8000/

    72.png
    访问product时
    73.png

    此时已经建立好了两个http服务

    3、监控服务器文件的变化

    因为当修改文件时,重新刷新地址,内容是不会变化的,必须要重启服务才可以更新内容,所以下面安装可以监控源代码变化并自动重启服务器的工具nodemonitor。
    1.安装nodemon
    ···
    npm install -g nodemon
    ···

    2.用nodemon来启动服务器

    nodemon build/auction_serve.js
    

    当修改内容时


    74.png

    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.刷新浏览器

    75.png

    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.结果

    76.png
    77.png

    <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<any>;
    
      // 用来和模版做数据绑定的数组
      myproducts:Array<any> = [];
    
      // 将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.修改模版

    <div>
        商品信息
    </div>
    <ul>
        <!-- 添加async管道 -->
        <li *ngFor="let pro of myproducts | async">
            {{pro.title}}
        </li>
    </ul>
    

    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<any>;
    
      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<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();
          }
        )
      }
    
      // 向服务器发送一个消息
      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.修改模版

    <button (click)="sendMessagegToServer">向服务器发消息</button>
    

    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);
    

    相关文章

      网友评论

      本文标题:angular (6)与服务器通信

      本文链接:https://www.haomeiwen.com/subject/obqcyftx.html