Angular4-在线竞拍应用-与服务器通信

来源:互联网 发布:对linux系统的认识 编辑:程序博客网 时间:2024/04/30 00:39

创建web服务器

  • 使用Nodejs创建服务器
  • 使用Express创建restful的http服务
  • 监控服务器文件的变化

用webstorm建立一个名为server的空项目

在文件中,执行命令npm init -y

执行cnpm i @types/node –save

在server中新建一个tsconfig.json

{  "compilerOptions": {    "module": "commonjs",    "target": "es5",    "emitDecoratorMetadata": true,    "experimentalDecorators": true,    "outDir": "build",    "lib": ["es6"]  },  "exclude": [    "node_modules"  ]}

配置一下webstorm

Settings,Languages & Frameworks,TypeScript,把Enable TypeScript Compiler前边的对勾打上。

在server中建一个文件server,在里边新建一个hello_server.ts文件

import * as http from 'http'const server=http.createServer(function (request,response) {    response.end('Hello World\n');}).listen(8888);

执行node build/hello_server.js

之后访问http://localhost:8888/

就会看到页面显示Hello World

执行cnpm install express –save 来安装express框架

执行cnpm install @types/express –save

在第二个server中新建一个auction_server.ts

import * as express from 'express';const app=express();app.get('/',(req,res)=>{    res.send("Hello Express");});app.get('/products',(req,res)=>{    res.send("接收到商品查询请求");});const server=app.listen(8888,"localhost",()=>{   console.log("服务器已启动,地址是:http://localhost:8888");});

执行node build/auction_server.js

执行cnpm install -g nodemon 可以改变文件后不用重启服务

执行nodemon build/auction_server.js 来启动服务

修改auction_server.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,                public categories: Array<string>) {    }}const products:Product[]= [    new Product(1, '第一个商品', 1.99, 3.5, '这是第一个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品']),    new Product(2, '第二个商品', 2.99, 2.5, '这是第二个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品', '硬件设备']),    new Product(3, '第三个商品', 3.99, 4.5, '这是第三个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品']),    new Product(4, '第四个商品', 4.99, 1.5, '这是第四个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品']),    new Product(5, '第五个商品', 5.99, 3.5, '这是第五个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品']),    new Product(6, '第五个商品', 6.99, 2.5, '这是第六个商品,是我在学习慕课网Angular入门实战时创建的', ['电子产品'])];app.get('/',(req,res)=>{    res.send("Hello Express");});app.get('/products',(req,res)=>{    res.json(products);});const server=app.listen(8888,"localhost",()=>{   console.log("服务器已启动,地址是:http://localhost:8888");});

然后访问http://localhost:8888/products

添加一个方法

app.get('/product/:id', (req, res) => {    res.json(products.find((product) => product.id == req.params.id));});

然后访问http://localhost:8888/product/3

Http通讯

新建一个项目client

打开node_modules/@angular/http/src/http.d.ts

import { Observable } from 'rxjs/Observable';import { RequestOptions } from './base_request_options';import { ConnectionBackend, RequestOptionsArgs } from './interfaces';import { Request } from './static_request';import { Response } from './static_response';/** * Performs http requests using `XMLHttpRequest` as the default backend. * * `Http` is available as an injectable class, with methods to perform http requests. Calling * `request` returns an `Observable` which will emit a single {@link Response} when a * response is received. * * ### Example * * ```typescript * import {Http, HTTP_PROVIDERS} from '@angular/http'; * import 'rxjs/add/operator/map' * @Component({ *   selector: 'http-app', *   viewProviders: [HTTP_PROVIDERS], *   templateUrl: 'people.html' * }) * class PeopleComponent { *   constructor(http: Http) { *     http.get('people.json') *       // Call map on the response observable to get the parsed people object *       .map(res => res.json()) *       // Subscribe to the observable to get the parsed people object and attach it to the *       // component *       .subscribe(people => this.people = people); *   } * } * ``` * * * ### Example * * ``` * http.get('people.json').subscribe((res:Response) => this.people = res.json()); * ``` * * The default construct used to perform requests, `XMLHttpRequest`, is abstracted as a "Backend" ( * {@link XHRBackend} in this case), which could be mocked with dependency injection by replacing * the {@link XHRBackend} provider, as in the following example: * * ### Example * * ```typescript * import {BaseRequestOptions, Http} from '@angular/http'; * import {MockBackend} from '@angular/http/testing'; * var injector = Injector.resolveAndCreate([ *   BaseRequestOptions, *   MockBackend, *   {provide: Http, useFactory: *       function(backend, defaultOptions) { *         return new Http(backend, defaultOptions); *       }, *       deps: [MockBackend, BaseRequestOptions]} * ]); * var http = injector.get(Http); * http.get('request-from-mock-backend.json').subscribe((res:Response) => doSomething(res)); * ``` * * @experimental */export declare class Http {    protected _backend: ConnectionBackend;    protected _defaultOptions: RequestOptions;    constructor(_backend: ConnectionBackend, _defaultOptions: RequestOptions);    /**     * Performs any type of http request. First argument is required, and can either be a url or     * a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}     * object can be provided as the 2nd argument. The options object will be merged with the values     * of {@link BaseRequestOptions} before performing the request.     */    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `get` http method.     */    get(url: string, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `post` http method.     */    post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `put` http method.     */    put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `delete` http method.     */    delete(url: string, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `patch` http method.     */    patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `head` http method.     */    head(url: string, options?: RequestOptionsArgs): Observable<Response>;    /**     * Performs a request with `options` http method.     */    options(url: string, options?: RequestOptionsArgs): Observable<Response>;}/** * @experimental */export declare class Jsonp extends Http {    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions);    /**     * Performs any type of http request. First argument is required, and can either be a url or     * a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}     * object can be provided as the 2nd argument. The options object will be merged with the values     * of {@link BaseRequestOptions} before performing the request.     *     * @security Regular XHR is the safest alternative to JSONP for most applications, and is     * supported by all current browsers. Because JSONP creates a `<script>` element with     * contents retrieved from a remote source, attacker-controlled data introduced by an untrusted     * source could expose your application to XSS risks. Data exposed by JSONP may also be     * readable by malicious third-party websites. In addition, JSONP introduces potential risk for     * future security issues (e.g. content sniffing).  For more detail, see the     * [Security Guide](http://g.co/ng/security).     */    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response>;}

http服务就是一个标准的TypeScript的类,跟我们自己写的服务是一样的。

 get(url: string, options?: RequestOptionsArgs): Observable<Response>;

get就是发get请求的,post就是发post请求的,put就是发put请求的。。。

url就是发订单请求的 路径,这是必须的参数

options是可选参数,

每个方法都返回一个Observable,也就是可观测的流,流中的元素类型是Response,通过订阅这个流来获取服务端响应的数据,RequestOptionsArgs定义了一组与请求相关的参数

export interface RequestOptionsArgs {    url?: string | null;    method?: string | RequestMethod | null;    /** @deprecated from 4.0.0. Use params instead. */    search?: string | URLSearchParams | {        [key: string]: any | any[];    } | null;    params?: string | URLSearchParams | {        [key: string]: any | any[];    } | null;    headers?: Headers | null;    body?: any;    withCredentials?: boolean | null;    responseType?: ResponseContentType | null;}

其中url,method,body可以由调用的方法来决定

一般只会用这个方法来传递请求头headers

新建一个组件ng g component product

修改product.component.ts

import {Component, OnInit} from '@angular/core';import {Http} from '@angular/http';import {Observable} from 'rxjs/Observable';import 'rxjs/Rx';@Component({  selector: 'app-product',  templateUrl: './product.component.html',  styleUrls: ['./product.component.css']})export class ProductComponent implements OnInit {  dataSource: Observable<any>;//用来接收http服务返回的流  products: Array<any> = [];  constructor(private http: Http) {    this.dataSource=this.http.get('/api/products')      .map((res)=>res.json());  }  ngOnInit() {    this.dataSource.subscribe(      (data)=>this.products=data    );  }}

修改product.component.html

<p>  商品信息</p><ul>  <li *ngFor="let product of products">    {{product.title}}  </li></ul>

修改app.component.html

<app-product></app-product>

在client下新建一个配置文件proxy.conf.json。当头路径为/api时,都转发为localhost:8888

{  "/api":{    "target":"http://localhost:8888"  }}

修改package.json,让服务启动的时候加载proxy.conf.json文件

"start": "ng serve --proxy-config proxy.conf.json",

把服务端的地址前面都加上/api

app.get('/api/products',app.get('/api/product/:id',

启动服务,访问http://localhost:4200/,就可以看到商品的名称了。

http请求的发送并不是由get方法触发的而是由subscribe触发的

另一种通过管道的写法

修改product.component.ts

export class ProductComponent implements OnInit {  products: Observable<any>;  constructor(private http: Http) {    this.products=this.http.get('/api/products')      .map((res)=>res.json());  }  ngOnInit() {  }}

修改product.component.html

<p>  商品信息</p><ul>  <li *ngFor="let product of products | async">    {{product.title}}  </li></ul>

添加请求头

import {Component, OnInit} from '@angular/core';import {Http,Headers} from '@angular/http';import {Observable} from 'rxjs/Observable';import 'rxjs/Rx';@Component({  selector: 'app-product',  templateUrl: './product.component.html',  styleUrls: ['./product.component.css']})export class ProductComponent implements OnInit {  products: Observable<any>;  constructor(private http: Http) {    let myHeaders: Headers = new Headers();    myHeaders.append("Authorization", "Basic 123456")    this.products = this.http.get('/api/products', {headers: myHeaders})      .map((res) => res.json());  }  ngOnInit() {  }}

WebSocket通讯

这里写图片描述

http协议在同一时间是能是发送请求或者接收响应。不能同时进行。

而websocket协议可以在发送请求的时候也可以接收数据。

是一个长连接协议,不需要在每次发送或接收时建立连接,延迟更低

不需要每次都携带一些连接相关的信息,因此传递的信息少。

在server项目中安装ws相关的包cnpm install ws –save

执行cnpm install @types/ws –save-dev

websocket不是一个请求响应的协议。服务器和客户端都可以主动发送请求。

这里写图片描述

修改server项目中的auction_server.ts

import {Server} from 'ws';const wsServer = new Server({port: 8085});wsServer.on('connection',  websocket => {    websocket.send("这个消息是服务器主动推送的");});

在机器的8085端口创建一个服务器,当有任何一个客户端连接到这个服务器的时候,给这个客户端推送一个消息。

htt通信p是通过订阅http服务的get或post方法返回的流来处理服务器的响应数据

但是Angular并没有提供一个类似http服务端的类来从websocket中产生一个流,所以要自己写一个服务来返回流。

在client项目新生成一个服务ng g service shared/webSocket

修改web-socket.service.ts

import {Injectable} from '@angular/core';import {Observable} from "rxjs";@Injectable()export class WebSocketService {  ws: WebSocket;  constructor() {  }  /**   * 这个方法返回一个流,流中包括服务器推送的消息   * @param {string} url   * @returns {Observable<any>}   */  createObservableSocket(url: string): Observable<any> {    //创建一个websocket对象,这个对象会根据传进去的url去连接指定的websocket服务器    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);  }}

新建一个组件ng g component webSocket

修改web-socket.component.ts

import {Component, OnInit} from '@angular/core';import {WebSocketService} from "../shared/web-socket.service";@Component({  selector: 'app-web-socket',  templateUrl: './web-socket.component.html',  styleUrls: ['./web-socket.component.css']})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");  }}

修改web-socket.component.html

<button (click)="sendMessageToServer()">向服务器发送数据</button>

修改app.component.html

<app-product></app-product><app-web-socket></app-web-socket>

修改app.module.ts

providers: [WebSocketService],

修改server中的auction_server.ts

const wsServer = new Server({port: 8085});wsServer.on('connection',  websocket => {    websocket.send("这个消息是服务器主动推送的");    websocket.on("message",message=>{        console.log("接受到消息:"+message)    })});

之后访问http://localhost:4200/,查看浏览器的控制台会看到“这个消息是服务器主动推送的”。

然后点击按钮,查看server项目的控制台会看到“接受到消息:Hello from client”

现在这种情况是只有在客户端连接的时候服务器才会推送消息,如何在任何需要的时候推送消息呢?

修改auction_server.ts,添加

setInterval(()=>{   if(wsServer.clients){       wsServer.clients.forEach(client=>{           client.send("这是定时推送");       })   } },2000);

遍历每个客户端,每2秒给每个客户端推送消息

阅读全文
0 0
原创粉丝点击