WebSocket с угловым универсальным

#node.js #angular #express #websocket #angular-universal

#node.js #angular #экспресс #websocket #angular-универсальный

Вопрос:

Я пытаюсь добавить веб-сокеты на сервер, который использует angular universal. Насколько я могу судить, express обрабатывает мой запрос до того, как он попадет в мои сокеты, но я могу ошибаться в этом.

Я получаю эту ошибку в Chrome: WebSocket connection to 'ws://localhost:4200/socket' failed: Connection closed before receiving a handshake response

и я получаю эту ошибку в firefox: Firefox can’t establish a connection to the server at ws://localhost:4200/socket.

когда я запускаю отдельный сервер nodejs без кода angular, websockets работают нормально.

Вот соответствующая часть моего server.ts

 import 'zone.js/dist/zone-node'

import { ngExpressEngine } from '@nguniversal/express-engine'
import * as express from 'express'
import { join } from 'path'

import { AppServerModule } from './src/main.server'
import { APP_BASE_HREF } from '@angular/common'
import { existsSync } from 'fs'

import * as WebSocket from 'ws'

// The Express app is exported so that it can be used by serverless Functions.
export function app() {
  const server = express()
  const distFolder = join(process.cwd(), 'dist/CAHClone/browser')
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }))

  server.set('view engine', 'html')
  server.set('views', distFolder)

  server.use(express.json())

  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }))

  // All regular routes use the Universal engine
  server.get('*', (req, res, next) => {
    if (req.url === '/socket') return next() // leave '/socket' open for the websockets
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] })
  })

  return server
}

function run() {
  const port = process.env.PORT || 4000

  // Start up the Node server
  const expressApp = app()

  const server = expressApp.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`)
  })

  // Websockets
  const wss = setupWebsockets(server)
}

function setupWebsockets(server) {
  const wss = new WebSocket.Server({ server, path: '/socket' })
  
  wss.on('connection', ws => {
    console.log('Client connected.')
    ws.send({message: 'Hi there!'})
  })
  
  wss.on('message', msg => {
    console.log('Client said: '   msg.toString())
  })

  return wss
}

declare const __non_webpack_require__: NodeRequire
const mainModule = __non_webpack_require__.main
const moduleFilename = mainModule amp;amp; mainModule.filename || ''
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run()
}

export * from './src/main.server'
 

И вот server.js файл, который работает без кода, связанного с angular

 const express = require('express')
const WebSocket = require('ws')
const { join } = require('path')
const { existsSync } = require('fs')

// The Express app is exported so that it can be used by serverless Functions.
function app() {
  const server = express()

  server.use(express.json())

  server.use('*', (req, res, next) => {
    if (req.url === '/socket') return next()
    res.end('Hello, world!')
  })

  return server
}

function setupWebsockets(server) {
  const wss = new WebSocket.Server({ server, path: '/socket' })
  console.log('set up websocket server');

  wss.on('connection', ws => {
    console.log('Client connected.');
    ws.send('Hi there!')
  })

  wss.on('message', msg => {
    console.log('Client said: '   msg.toString());
  })
}

function run() {
  const port = process.env.PORT || 4000

  const expressApp = app()

  const server = expressApp.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`)
  })

  // Websockets
  const wsServer = setupWebsockets(server)
}

run()
 

Может ли кто-нибудь помочь мне понять, какая часть angular universal нарушает мои websockets и как это исправить?

Комментарии:

1. Вы пытаетесь подключиться к порту 4200.. но ваши серверы, похоже, работают на 4000 ..?

2. @MikeOne Спасибо, но я не думаю, что это проблема, angular, похоже, устанавливает для process.port.env значение 4200 при запуске npm run dev:srr . Я внимательно посмотрю на порты, чтобы увидеть, есть ли там что-то не так. Для сервера JS я намеренно использую 4000, и я подключаюсь к нему при тестировании.

3. Проблема на самом деле, похоже, связана с портом. Angular использует то, что кажется случайным портом, а также 4200, и веб-сокеты работают на этом случайном порту, но не на 4200. Я продолжу расследование, но если у кого-нибудь есть дополнительная информация о том, как это работает, пожалуйста, дайте мне знать.

4. Обновление: это работает нормально, если я запускаю npm run build:ssr , за которым следует npm run serve:ssr , проблема, похоже, связана со средой разработки, настроенной с npm run dev:ssr

Ответ №1:

Я столкнулся с этой проблемой с модулем ‘ws’ и передачей на экспресс-сервер. Попробуйте создать свой сервер с помощью модуля «http» и передать его как в express, так и в «ws». Я также рекомендую позаботиться о любой авторизации, которую вы собираетесь выполнить в случае «обновления», если это необходимо.