angular客户端与web服务器Websocket交互,使用JSON转换数据出错

问题描述

我在使用Angular搭建一个客户端,希望通过点击页面上的关注商品,就能从服务器获取实时更新的最新价格。可当我点击客户端按钮时,报出core.js:1633 ERROR SyntaxError: Unexpected token 这 in JSON at position 0的异常。浏览器调试错误如下:
图片描述
图片描述
图片描述

已经困扰我两天了,网上能找到试的方法都试了,也解决不了。说是有可能是运用JSON转化客户端与服务器数据时JSON.stringify和JSON.parse的格式错误。可我还是找不出来啊,求大佬们帮帮忙。

相关代码

客户端

product-detail.component.html

<div class="thumbnail">
  <img src="http://temp.im/820x300">
  <div>
    <h4 class="pull-right">{{product?.price}}</h4>
    <h4>{{product?.price}}</h4>
    <p>{{product?.desc}}</p>
  </div>
  <div>
    <p class="pull-right">{{comments?.length}}</p>
    <p>
      <app-stars [rating]="product?.rating"></app-stars>
    </p>
  </div>
</div>

<div class="thumbnail">
  <button class="btn btn-default btn-lg" [class.active]="isWatched" (click)="watchProduct()">
    {{isWatched?'取消关注':'关注'}}
  </button>
  <label>最新出价:{{currentBid | number:'.2-2'}}元</label>
</div>

<div class="well">
  <div>
    <button class="btn btn-success" (click)="isCommentHidden = !isCommentHidden">发表评论</button>
  </div>
  <div [hidden]="isCommentHidden">
    <div><app-stars [(rating)]="newRating" [readonly]="false"></app-stars></div>
    <div><textarea [(ngModel)]="newComment"></textarea></div>
    <div><button class="btn" (click)="addComment()">提交</button></div>
  </div>
  <div class="row" *ngFor="let comment of comments">
    <hr>
    <div class="col-md-12">
      <app-stars [rating]="comment.rating"></app-stars>
      <span>{{comment.user}}</span>
      <span class="pull-right">{{comment.timestamp}}</span>
      <p></p>
      <p>{{comment.content}}</p>
    </div>
  </div>
</div>

product-detail.component.ts

import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {Comment, Product, ProductService} from "../shared/product.service";
import {WeSocketService} from '../shared/we-socket.service';

@Component({
  selector: 'app-product-detail',
  templateUrl: './product-detail.component.html',
  styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
  product: Product;
  comments: Comment [];
  isWatched: boolean = false;
  currentBid: number;

  newRating: number = 5;
  newComment: string = '';
  isCommentHidden: boolean = true;
  constructor(private routInfo: ActivatedRoute,
              private productService: ProductService,
              private webService: WeSocketService
  ) { }

  ngOnInit() {
    let productId: number = this.routInfo.snapshot.params['productId'];
    this.productService.getProduct(productId).subscribe(
      product => {
        this.product = product;
        this.currentBid = this.product.price;
      }
      );
    this.productService.getProductForProductId(productId).subscribe(
      comment => this.comments = comment
    );
  }

  addComment() {
    let comment = new Comment(0, this.product.id, new Date().toISOString(), 'SomeOne', this.newRating, this.newComment);
    this.comments.unshift(comment);

    let sum = this.comments.reduce((sum, comment) => sum + comment.rating, 0);
    this.product.rating = sum / this.comments.length;

    this.newComment = null;
    this.newRating = 5;
    this.isCommentHidden = true;
  }

  watchProduct() {
    this.isWatched = !this.isWatched;

    this.webService.creatObservableSocket('ws://localhost:8085', this.product.id)
      .subscribe(
        products => {
          let produc = products.find(p => p.productId === this.product.id);
          this.currentBid = produc.bid;
        }
      );
  }
}

we-socket.service.ts

import { Injectable } from '@angular/core';
import {observable, Observable} from 'rxjs';
import 'rxjs/Rx';

@Injectable({
  providedIn: 'root'
})
export class WeSocketService {

  ws: WebSocket;

  constructor() { }

  creatObservableSocket(url: string, id: number): Observable<any> {
    this.ws = new WebSocket(url);
    return new Observable<string>(
      observable => {
        this.ws.onmessage = (event) => observable.next(event.data);
        this.ws.onerror = (event) => observable.error(event);
        this.ws.onclose = (event) => observable.complete();
        this.ws.onopen = (event) => this.sendMessage({productId: id});
      }
    ).map(message => {JSON.parse(message)});
  }

  sendMessage(message: any) {
    this.ws.send(JSON.stringify(message));
  }
}

服务器端
auction_service.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,
        public categories: Array<string>
    ) {
    }
}
export class Comment {
    constructor(
        public id: number,
        public productId: number,
        public timestamp: string,
        public user: string,
        public rating: number,
        public content: string
    ) {
    }
}


const products: Product[] = [
    new Product(1, '第一个商品', 1.99, 1.5, '这是第一个商品,是我用Angular创建的。', ['电子产品', '硬件设备']),
    new Product(2, '第二个商品', 2.99, 3.5, '这是第二个商品,是我用Angular创建的。', [ '硬件设备']),
    new Product(3, '第三个商品', 3.99, 4.5, '这是第三个商品,是我用Angular创建的。', ['二次元', '硬件设备']),
    new Product(4, '第四个商品', 4.99, 2.5, '这是第四个商品,是我用Angular创建的。', ['电子产品']),
    new Product(5, '第五个商品', 5.99, 1.5, '这是第五个商品,是我用Angular创建的。', ['电子产品', '二次元']),
    new Product(6, '第六个商品', 6.99, 3.5, '这是第六个商品,是我用Angular创建的。', ['二次元']),
];

const comments: Comment[] = [
    new Comment(1, 1, '2018-02-22 1:15:13', '张三', 3, '这东西可以啊~'),
    new Comment(2, 1, '2018-03-02 21:15:13', '李四', 2, '一般一般~'),
    new Comment(3, 1, '2018-06-22 15:12:03', '王五', 4, '马马虎虎吧,到手了就更好了~'),
    new Comment(4, 2, '2018-04-22 17:20:13', '赵柳', 1, '这什么玩意儿啊……'),
    new Comment(5, 2, '2018-07-22 11:15:13', '吕狗蛋', 4, '超想要啊'),
]

app.get('/', (req, res) =>{
    res.send('Hello Express')
});

app.get('/api/products', (req, res) =>{
    let result = products;
    let params = req.query;
    if (params.title){
        result = result.filter((p) => p.title.indexOf(params.title) !== -1);
    }
    if (params.price && result.length > 0){
        result = result.filter((p) => p.price <= parseInt(params.price));
    }
    if (params.category && result.length >0){
        result = result.filter((p) => p.categories.indexOf(params.category) !== -1)
    }

    res.json(result);
});

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

app.get('/api/product/:id/comments', (req, res) =>{
    res.json(comments.filter((comment: Comment) => comment.productId == req.params.id))
});

const server = app.listen(8000,'localhost', () =>{
    console.log('服务器已启动,地址是:http://localhost:8000');
});

const subscriptions = new Map<any, number[]>();

const wsServer = new Server({port: 8085});
wsServer.on("connection", websocket =>{
    websocket.send('这个消息是服务器主动推送的');
    websocket.on('message', message =>{
        let messageObj = JSON.parse(message);
        let productIds = subscriptions.get(websocket) || [];
        subscriptions.set(websocket, [...productIds, messageObj.productId]);
    });
});

const currentBids = new Map<number, number>();

setInterval(() =>{
    products.forEach(p =>{
        let currentBid = currentBids.get(p.id) || p.price;
        let newBid = currentBid + Math.random()*5;
        currentBids.set(p.id, newBid);
    })

    subscriptions.forEach((productIds: number[], ws) => {
        if (ws.readyState === 1){
            let newBids = productIds.map(pid => ({
                productId: pid,
                bid: currentBids.get(pid)
            }));
            ws.send(JSON.stringify(newBids));
        }else {
            subscriptions.delete(ws);
        }
    });
},2000);

希望最终能通过商品页面的关注商品,然后可以从服务器获取一个实时刷新的价格。

阅读 2.7k
1 个回答

解决了,忘了贴上来,这个

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题