UNPKG

11.6 kBMarkdownView Raw
1# ws: a Node.js WebSocket library
2
3[![Version npm](https://img.shields.io/npm/v/ws.svg)](https://www.npmjs.com/package/ws)
4[![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg)](https://travis-ci.org/websockets/ws)
5[![Windows Build](https://ci.appveyor.com/api/projects/status/github/websockets/ws?branch=master&svg=true)](https://ci.appveyor.com/project/lpinca/ws)
6[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/r/websockets/ws?branch=master)
7
8ws is a simple to use, blazing fast, and thoroughly tested WebSocket client
9and server implementation.
10
11Passes the quite extensive Autobahn test suite: [server][server-report],
12[client][client-report].
13
14**Note**: This module does not work in the browser. The client in the docs is a
15reference to a back end with the role of a client in the WebSocket
16communication. Browser clients must use the native
17[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) object.
18To make the same code work seamlessly on Node.js and the browser, you can use
19one of the many wrappers available on npm, like
20[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
21
22## Table of Contents
23
24* [Protocol support](#protocol-support)
25* [Installing](#installing)
26 + [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance)
27* [API docs](#api-docs)
28* [WebSocket compression](#websocket-compression)
29* [Usage examples](#usage-examples)
30 + [Sending and receiving text data](#sending-and-receiving-text-data)
31 + [Sending binary data](#sending-binary-data)
32 + [Server example](#server-example)
33 + [Broadcast example](#broadcast-example)
34 + [ExpressJS example](#expressjs-example)
35 + [echo.websocket.org demo](#echowebsocketorg-demo)
36 + [Other examples](#other-examples)
37* [Error handling best practices](#error-handling-best-practices)
38* [FAQ](#faq)
39 + [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
40 + [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
41 + [How to connect via a proxy?](#how-to-connect-via-a-proxy)
42* [Changelog](#changelog)
43* [License](#license)
44
45## Protocol support
46
47* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
48* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
49
50## Installing
51
52```
53npm install --save ws
54```
55
56### Opt-in for performance and spec compliance
57
58There are 2 optional modules that can be installed along side with the ws
59module. These modules are binary addons which improve certain operations.
60Prebuilt binaries are available for the most popular platforms so you don't
61necessarily need to have a C++ compiler installed on your machine.
62
63- `npm install --save-optional bufferutil`: Allows to efficiently perform
64 operations such as masking and unmasking the data payload of the WebSocket
65 frames.
66- `npm install --save-optional utf-8-validate`: Allows to efficiently check
67 if a message contains valid UTF-8 as required by the spec.
68
69## API docs
70
71See [`/doc/ws.md`](./doc/ws.md) for Node.js-like docs for the ws classes.
72
73## WebSocket compression
74
75ws supports the [permessage-deflate extension][permessage-deflate] which
76enables the client and server to negotiate a compression algorithm and its
77parameters, and then selectively apply it to the data payloads of each
78WebSocket message.
79
80The extension is disabled by default on the server and enabled by default on
81the client. It adds a significant overhead in terms of performance and memory
82consumption so we suggest to enable it only if it is really needed.
83
84Note that Node.js has a variety of issues with high-performance compression,
85where increased concurrency, especially on Linux, can lead to
86[catastrophic memory fragmentation][node-zlib-bug] and slow performance.
87If you intend to use permessage-deflate in production, it is worthwhile to set
88up a test representative of your workload and ensure Node.js/zlib will handle
89it with acceptable performance and memory usage.
90
91Tuning of permessage-deflate can be done via the options defined below. You can
92also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
93into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
94
95See [the docs][ws-server-options] for more options.
96
97```js
98const WebSocket = require('ws');
99
100const wss = new WebSocket.Server({
101 port: 8080,
102 perMessageDeflate: {
103 zlibDeflateOptions: { // See zlib defaults.
104 chunkSize: 1024,
105 memLevel: 7,
106 level: 3,
107 },
108 zlibInflateOptions: {
109 chunkSize: 10 * 1024
110 },
111 // Other options settable:
112 clientNoContextTakeover: true, // Defaults to negotiated value.
113 serverNoContextTakeover: true, // Defaults to negotiated value.
114 clientMaxWindowBits: 10, // Defaults to negotiated value.
115 serverMaxWindowBits: 10, // Defaults to negotiated value.
116 // Below options specified as default values.
117 concurrencyLimit: 10, // Limits zlib concurrency for perf.
118 threshold: 1024, // Size (in bytes) below which messages
119 // should not be compressed.
120 }
121});
122```
123
124The client will only use the extension if it is supported and enabled on the
125server. To always disable the extension on the client set the
126`perMessageDeflate` option to `false`.
127
128```js
129const WebSocket = require('ws');
130
131const ws = new WebSocket('ws://www.host.com/path', {
132 perMessageDeflate: false
133});
134```
135
136## Usage examples
137
138### Sending and receiving text data
139
140```js
141const WebSocket = require('ws');
142
143const ws = new WebSocket('ws://www.host.com/path');
144
145ws.on('open', function open() {
146 ws.send('something');
147});
148
149ws.on('message', function incoming(data) {
150 console.log(data);
151});
152```
153
154### Sending binary data
155
156```js
157const WebSocket = require('ws');
158
159const ws = new WebSocket('ws://www.host.com/path');
160
161ws.on('open', function open() {
162 const array = new Float32Array(5);
163
164 for (var i = 0; i < array.length; ++i) {
165 array[i] = i / 2;
166 }
167
168 ws.send(array);
169});
170```
171
172### Server example
173
174```js
175const WebSocket = require('ws');
176
177const wss = new WebSocket.Server({ port: 8080 });
178
179wss.on('connection', function connection(ws) {
180 ws.on('message', function incoming(message) {
181 console.log('received: %s', message);
182 });
183
184 ws.send('something');
185});
186```
187
188### Broadcast example
189
190```js
191const WebSocket = require('ws');
192
193const wss = new WebSocket.Server({ port: 8080 });
194
195// Broadcast to all.
196wss.broadcast = function broadcast(data) {
197 wss.clients.forEach(function each(client) {
198 if (client.readyState === WebSocket.OPEN) {
199 client.send(data);
200 }
201 });
202};
203
204wss.on('connection', function connection(ws) {
205 ws.on('message', function incoming(data) {
206 // Broadcast to everyone else.
207 wss.clients.forEach(function each(client) {
208 if (client !== ws && client.readyState === WebSocket.OPEN) {
209 client.send(data);
210 }
211 });
212 });
213});
214```
215
216### ExpressJS example
217
218```js
219const express = require('express');
220const http = require('http');
221const url = require('url');
222const WebSocket = require('ws');
223
224const app = express();
225
226app.use(function (req, res) {
227 res.send({ msg: "hello" });
228});
229
230const server = http.createServer(app);
231const wss = new WebSocket.Server({ server });
232
233wss.on('connection', function connection(ws, req) {
234 const location = url.parse(req.url, true);
235 // You might use location.query.access_token to authenticate or share sessions
236 // or req.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
237
238 ws.on('message', function incoming(message) {
239 console.log('received: %s', message);
240 });
241
242 ws.send('something');
243});
244
245server.listen(8080, function listening() {
246 console.log('Listening on %d', server.address().port);
247});
248```
249
250### echo.websocket.org demo
251
252```js
253const WebSocket = require('ws');
254
255const ws = new WebSocket('wss://echo.websocket.org/', {
256 origin: 'https://websocket.org'
257});
258
259ws.on('open', function open() {
260 console.log('connected');
261 ws.send(Date.now());
262});
263
264ws.on('close', function close() {
265 console.log('disconnected');
266});
267
268ws.on('message', function incoming(data) {
269 console.log(`Roundtrip time: ${Date.now() - data} ms`);
270
271 setTimeout(function timeout() {
272 ws.send(Date.now());
273 }, 500);
274});
275```
276
277### Other examples
278
279For a full example with a browser client communicating with a ws server, see the
280examples folder.
281
282Otherwise, see the test cases.
283
284## Error handling best practices
285
286```js
287// If the WebSocket is closed before the following send is attempted
288ws.send('something');
289
290// Errors (both immediate and async write errors) can be detected in an optional
291// callback. The callback is also the only way of being notified that data has
292// actually been sent.
293ws.send('something', function ack(error) {
294 // If error is not defined, the send has been completed, otherwise the error
295 // object will indicate what failed.
296});
297
298// Immediate errors can also be handled with `try...catch`, but **note** that
299// since sends are inherently asynchronous, socket write failures will *not* be
300// captured when this technique is used.
301try { ws.send('something'); }
302catch (e) { /* handle error */ }
303```
304
305## FAQ
306
307### How to get the IP address of the client?
308
309The remote IP address can be obtained from the raw socket.
310
311```js
312const WebSocket = require('ws');
313
314const wss = new WebSocket.Server({ port: 8080 });
315
316wss.on('connection', function connection(ws, req) {
317 const ip = req.connection.remoteAddress;
318});
319```
320
321When the server runs behind a proxy like NGINX, the de-facto standard is to use
322the `X-Forwarded-For` header.
323
324```js
325wss.on('connection', function connection(ws, req) {
326 const ip = req.headers['x-forwarded-for'];
327});
328```
329
330### How to detect and close broken connections?
331
332Sometimes the link between the server and the client can be interrupted in a
333way that keeps both the server and the client unaware of the broken state of the
334connection (e.g. when pulling the cord).
335
336In these cases ping messages can be used as a means to verify that the remote
337endpoint is still responsive.
338
339```js
340const WebSocket = require('ws');
341
342const wss = new WebSocket.Server({ port: 8080 });
343
344function noop() {}
345
346function heartbeat() {
347 this.isAlive = true;
348}
349
350wss.on('connection', function connection(ws) {
351 ws.isAlive = true;
352 ws.on('pong', heartbeat);
353});
354
355const interval = setInterval(function ping() {
356 wss.clients.forEach(function each(ws) {
357 if (ws.isAlive === false) return ws.terminate();
358
359 ws.isAlive = false;
360 ws.ping(noop);
361 });
362}, 30000);
363```
364
365Pong messages are automatically sent in response to ping messages as required
366by the spec.
367
368### How to connect via a proxy?
369
370Use a custom `http.Agent` implementation like [https-proxy-agent][] or
371[socks-proxy-agent][].
372
373## Changelog
374
375We're using the GitHub [releases][changelog] for changelog entries.
376
377## License
378
379[MIT](LICENSE)
380
381[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
382[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
383[client-report]: http://websockets.github.io/ws/autobahn/clients/
384[server-report]: http://websockets.github.io/ws/autobahn/servers/
385[permessage-deflate]: https://tools.ietf.org/html/rfc7692
386[changelog]: https://github.com/websockets/ws/releases
387[node-zlib-bug]: https://github.com/nodejs/node/issues/8871
388[node-zlib-deflaterawdocs]: https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
389[ws-server-options]: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback