使用 RxJs WebSocketSubject 和 Angular Universal 时出现“ReferenceError: WebSocket is not defined”
Posted
技术标签:
【中文标题】使用 RxJs WebSocketSubject 和 Angular Universal 时出现“ReferenceError: WebSocket is not defined”【英文标题】:"ReferenceError: WebSocket is not defined" when using RxJs WebSocketSubject and Angular Universal 【发布时间】:2019-01-03 01:20:19 【问题描述】:我正在设置 angular 6.x univeral project 以利用其 s-s-r(服务器端渲染)功能。在我的应用程序中,我使用 RxJs 使用 websocket 通信。
更具体地说,我在我的 Angular 通用 6.x 项目中使用 WebSocketSubject
和 webSocket
,这在浏览器平台上运行良好。但是,在运行节点 Web 服务器(包含 s-s-r 内容(服务器端渲染))时,会引发错误:
ReferenceError: WebSocket 未定义
示例代码:
// not actually code from the reproduction repo
import WebSocketSubject, webSocket from 'rxjs/webSocket';
const socket: WebSocketSubject<any> = webSocket('wss://echo.websocket.org');
socket.subscribe(msg => doSomething(msg));
请注意,错误不会发生在应用程序的浏览器版本上(即ng serve
不会抛出错误),但只有在编译 s-s-r 内容并运行快递网络服务器。要重现错误,必须先运行构建:
# install dependencies
npm install
# build angular bundles for browser and server platforms
npm run build:client-and-server-bundles
# build the webserver
npm run webpack:server
# start the webserver
npm run serve:s-s-r
# the app is now being served at http://localhost:8081/
# open it in the browser and the error will occur: 'ReferenceError: WebSocket is not defined'
我还设置了reproduction repo。
我正在使用的环境:
运行时:Angular 6 RxJS 版本:6.2.0、6.2.1、6.2.2(全部测试)编辑 2018-08-02
我能够更准确地解决问题。看来,这也是一个 webpack 的问题。 Angular Universal 创建了一个 js 包,用于在节点服务器上运行 Angular 应用程序,但 Node 上本身没有 websocket 实现。因此,必须手动将其添加为依赖项(npm 包)。我尝试将它添加到 js 服务器包中(手动添加const WebSocket = require('ws');
,解决了问题(即 ReferenceError 消失了)。但是,当我将它添加到 TypeScript 代码中时,该代码稍后会被转编译到 js 包中开,它不会工作。
更多详情
webpack loaderts-loader
用于编译 TypeScript => javascript
在 package.json 中添加了 websocket 依赖:"ws": "^6.0.0"
尝试通过将const WebSocket = require('ws');
添加到未编译的 TypeScript 代码来引用 ws 依赖项将无法解决问题。会在js输出文件中编译成var WebSocket = __webpack_require__(333);
,无法解析依赖。
手动在编译的 js 文件中更改 var WebSocket = __webpack_require__(333);
=> const WebSocket = require('ws');
会解决问题,但当然这是一个 hack。
所以,问题是:
我可以“强制”webpack 编译依赖项const WebSocket = require('ws');
=> const WebSocket = require('ws');
(无更改)吗?
或者,在 Angular 通用 npm 包中注册此依赖项并创建拉取请求可能是更好的解决方案?
【问题讨论】:
在你的代码中是不是检查你是服务器端还是客户端,以便在浏览器中执行代码时使用套接字? @David 在 SO (***.com/questions/41700412/…) 上有一个类似的问题,建议只在客户端调用 websocket,这会使错误消失,但是,这不是我的解决方案。即使在服务器上执行代码,我也很想使用websocket。 这就是我的意思。既然代码是在服务端执行的,然后是客户端执行的,为什么还要使用 websockets 服务端呢? @David 所以它也被包含在服务器端呈现的页面中。如果我向我的 Angular 应用程序中的任何路由发出 http 请求,我想获得该特定路由的完整标记,因此它甚至应该包含 websocket 数据。 【参考方案1】:只需要这样:
// set WebSocket on global object
(global as any).WebSocket = require('ws');
当然,我们还需要 package.json 中的 ws
依赖项:
npm i ws -s
【讨论】:
您好,我正在使用 Angular 7,我想将它与 http 一起使用,而不是与 ws 或 wss 我如何完成它。【参考方案2】:我使用 websockets 创建了一个 npm 包。 为了提供服务器端 js 和浏览器 js 的兼容性,我使用此代码。
(注意:是打字稿)
if (typeof global !== 'undefined')
(global as any).WebSocket = require('ws');
就像你提到的,浏览器在其全局对象window
中已经有一个 WebSocket,但节点没有。
由于浏览器没有global
,所以这个简单的检查效果很好。
编译代码:
if (typeof global !== 'undefined')
global.WebSocket = require('ws');
【讨论】:
【参考方案3】:RxJS webSocket 函数可以接收一个 WebSocket 构造函数作为参数。这可以用来在像这样的非浏览器/通用环境中运行 webSocket。
const WebSocketConstructor = WebSocket || require('ws')
const socket: WebSocketSubject<any> = webSocket(
url: 'wss://echo.websocket.org',
WebSocketCtor: WebSocketConstructor,
);
【讨论】:
【参考方案4】:在 ES6 或类似的 nodeJS 应用中,你必须使用这个:
global.WebSocket = require('ws')
例如:
import WebSocketSubject, webSocket from 'rxjs/webSocket';
global.WebSocket = require('ws'); // <-- FIX ALL ERRORS
const subject = webSocket('ws://...');
没有更多错误。
我的第一个答案!!干杯
【讨论】:
以上是关于使用 RxJs WebSocketSubject 和 Angular Universal 时出现“ReferenceError: WebSocket is not defined”的主要内容,如果未能解决你的问题,请参考以下文章
从 WebSocketSubject 反序列化 Blob 对象