Angular client interacts with web server Websocket, error converting data using JSON

problem description

I"m using Angular to build a client, hoping to get the latest real-time prices from the server by clicking on the following items on the page. But when I click the client button, I report the exception of core.js:1633 ERROR SyntaxError: Unexpected token in JSON at position 0. Browser debugging errors are as follows:


has been bothering me for two days. I can find a way to try on the Internet, but I can"t solve it. It is said that it is possible to use JSON to convert client and server data in the wrong format of JSON.stringify and JSON.parse. But I still can"t find it. Ask the bosses for help.

related codes

client

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>
    

{{product?.desc}}

</div> <div> <p class="pull-right">{{comments?.length}}

<app-stars [rating]="product?.rating"></app-stars>

</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>

{{comment.content}}

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

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

hopes to eventually follow the item through the merchandise page, and then get a real-time refresh price from the server.

Menu