| # faye-websocket | |
| This is a general-purpose WebSocket implementation extracted from the | |
| [Faye](http://faye.jcoglan.com) project. It provides classes for easily building | |
| WebSocket servers and clients in Node. It does not provide a server itself, but | |
| rather makes it easy to handle WebSocket connections within an existing | |
| [Node](https://nodejs.org/) application. It does not provide any abstraction | |
| other than the standard [WebSocket | |
| API](https://html.spec.whatwg.org/multipage/comms.html#network). | |
| It also provides an abstraction for handling | |
| [EventSource](https://html.spec.whatwg.org/multipage/comms.html#server-sent-events) | |
| connections, which are one-way connections that allow the server to push data to | |
| the client. They are based on streaming HTTP responses and can be easier to access | |
| via proxies than WebSockets. | |
| ## Installation | |
| ``` | |
| $ npm install faye-websocket | |
| ``` | |
| ## Handling WebSocket connections in Node | |
| You can handle WebSockets on the server side by listening for HTTP Upgrade | |
| requests, and creating a new socket for the request. This socket object exposes | |
| the usual WebSocket methods for receiving and sending messages. For example this | |
| is how you'd implement an echo server: | |
| ```js | |
| var WebSocket = require('faye-websocket'), | |
| http = require('http'); | |
| var server = http.createServer(); | |
| server.on('upgrade', function(request, socket, body) { | |
| if (WebSocket.isWebSocket(request)) { | |
| var ws = new WebSocket(request, socket, body); | |
| ws.on('message', function(event) { | |
| ws.send(event.data); | |
| }); | |
| ws.on('close', function(event) { | |
| console.log('close', event.code, event.reason); | |
| ws = null; | |
| }); | |
| } | |
| }); | |
| server.listen(8000); | |
| ``` | |
| `WebSocket` objects are also duplex streams, so you could replace the | |
| `ws.on('message', ...)` line with: | |
| ```js | |
| ws.pipe(ws); | |
| ``` | |
| Note that under certain circumstances (notably a draft-76 client connecting | |
| through an HTTP proxy), the WebSocket handshake will not be complete after you | |
| call `new WebSocket()` because the server will not have received the entire | |
| handshake from the client yet. In this case, calls to `ws.send()` will buffer | |
| the message in memory until the handshake is complete, at which point any | |
| buffered messages will be sent to the client. | |
| If you need to detect when the WebSocket handshake is complete, you can use the | |
| `onopen` event. | |
| If the connection's protocol version supports it, you can call `ws.ping()` to | |
| send a ping message and wait for the client's response. This method takes a | |
| message string, and an optional callback that fires when a matching pong message | |
| is received. It returns `true` if and only if a ping message was sent. If the | |
| client does not support ping/pong, this method sends no data and returns | |
| `false`. | |
| ```js | |
| ws.ping('Mic check, one, two', function() { | |
| // fires when pong is received | |
| }); | |
| ``` | |
| ## Using the WebSocket client | |
| The client supports both the plain-text `ws` protocol and the encrypted `wss` | |
| protocol, and has exactly the same interface as a socket you would use in a web | |
| browser. On the wire it identifies itself as `hybi-13`. | |
| ```js | |
| var WebSocket = require('faye-websocket'), | |
| ws = new WebSocket.Client('ws://www.example.com/'); | |
| ws.on('open', function(event) { | |
| console.log('open'); | |
| ws.send('Hello, world!'); | |
| }); | |
| ws.on('message', function(event) { | |
| console.log('message', event.data); | |
| }); | |
| ws.on('close', function(event) { | |
| console.log('close', event.code, event.reason); | |
| ws = null; | |
| }); | |
| ``` | |
| The WebSocket client also lets you inspect the status and headers of the | |
| handshake response via its `statusCode` and `headers` properties. | |
| To connect via a proxy, set the `proxy` option to the HTTP origin of the proxy, | |
| including any authorization information, custom headers and TLS config you | |
| require. Only the `origin` setting is required. | |
| ```js | |
| var ws = new WebSocket.Client('ws://www.example.com/', [], { | |
| proxy: { | |
| origin: 'http://username:[email protected]', | |
| headers: { 'User-Agent': 'node' }, | |
| tls: { cert: fs.readFileSync('client.crt') } | |
| } | |
| }); | |
| ``` | |
| The `tls` value is an object that will be passed to | |
| [`tls.connect()`](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback). | |
| ## Subprotocol negotiation | |
| The WebSocket protocol allows peers to select and identify the application | |
| protocol to use over the connection. On the client side, you can set which | |
| protocols the client accepts by passing a list of protocol names when you | |
| construct the socket: | |
| ```js | |
| var ws = new WebSocket.Client('ws://www.example.com/', ['irc', 'amqp']); | |
| ``` | |
| On the server side, you can likewise pass in the list of protocols the server | |
| supports after the other constructor arguments: | |
| ```js | |
| var ws = new WebSocket(request, socket, body, ['irc', 'amqp']); | |
| ``` | |
| If the client and server agree on a protocol, both the client- and server-side | |
| socket objects expose the selected protocol through the `ws.protocol` property. | |
| ## Protocol extensions | |
| faye-websocket is based on the | |
| [websocket-extensions](https://github.com/faye/websocket-extensions-node) | |
| framework that allows extensions to be negotiated via the | |
| `Sec-WebSocket-Extensions` header. To add extensions to a connection, pass an | |
| array of extensions to the `:extensions` option. For example, to add | |
| [permessage-deflate](https://github.com/faye/permessage-deflate-node): | |
| ```js | |
| var deflate = require('permessage-deflate'); | |
| var ws = new WebSocket(request, socket, body, [], { extensions: [deflate] }); | |
| ``` | |
| ## Initialization options | |
| Both the server- and client-side classes allow an options object to be passed in | |
| at initialization time, for example: | |
| ```js | |
| var ws = new WebSocket(request, socket, body, protocols, options); | |
| var ws = new WebSocket.Client(url, protocols, options); | |
| ``` | |
| `protocols` is an array of subprotocols as described above, or `null`. | |
| `options` is an optional object containing any of these fields: | |
| - `extensions` - an array of | |
| [websocket-extensions](https://github.com/faye/websocket-extensions-node) | |
| compatible extensions, as described above | |
| - `headers` - an object containing key-value pairs representing HTTP headers to | |
| be sent during the handshake process | |
| - `maxLength` - the maximum allowed size of incoming message frames, in bytes. | |
| The default value is `2^26 - 1`, or 1 byte short of 64 MiB. | |
| - `ping` - an integer that sets how often the WebSocket should send ping frames, | |
| measured in seconds | |
| The client accepts some additional options: | |
| - `proxy` - settings for a proxy as described above | |
| - `net` - an object containing settings for the origin server that will be | |
| passed to | |
| [`net.connect()`](https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener) | |
| - `tls` - an object containing TLS settings for the origin server, this will be | |
| passed to | |
| [`tls.connect()`](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback) | |
| - `ca` - (legacy) a shorthand for passing `{ tls: { ca: value } }` | |
| ## WebSocket API | |
| Both server- and client-side `WebSocket` objects support the following API. | |
| - **`on('open', function(event) {})`** fires when the socket connection is | |
| established. Event has no attributes. | |
| - **`on('message', function(event) {})`** fires when the socket receives a | |
| message. Event has one attribute, **`data`**, which is either a `String` (for | |
| text frames) or a `Buffer` (for binary frames). | |
| - **`on('error', function(event) {})`** fires when there is a protocol error due | |
| to bad data sent by the other peer. This event is purely informational, you do | |
| not need to implement error recover. | |
| - **`on('close', function(event) {})`** fires when either the client or the | |
| server closes the connection. Event has two optional attributes, **`code`** | |
| and **`reason`**, that expose the status code and message sent by the peer | |
| that closed the connection. | |
| - **`send(message)`** accepts either a `String` or a `Buffer` and sends a text | |
| or binary message over the connection to the other peer. | |
| - **`ping(message, function() {})`** sends a ping frame with an optional message | |
| and fires the callback when a matching pong is received. | |
| - **`close(code, reason)`** closes the connection, sending the given status code | |
| and reason text, both of which are optional. | |
| - **`version`** is a string containing the version of the `WebSocket` protocol | |
| the connection is using. | |
| - **`protocol`** is a string (which may be empty) identifying the subprotocol | |
| the socket is using. | |
| ## Handling EventSource connections in Node | |
| EventSource connections provide a very similar interface, although because they | |
| only allow the server to send data to the client, there is no `onmessage` API. | |
| EventSource allows the server to push text messages to the client, where each | |
| message has an optional event-type and ID. | |
| ```js | |
| var WebSocket = require('faye-websocket'), | |
| EventSource = WebSocket.EventSource, | |
| http = require('http'); | |
| var server = http.createServer(); | |
| server.on('request', function(request, response) { | |
| if (EventSource.isEventSource(request)) { | |
| var es = new EventSource(request, response); | |
| console.log('open', es.url, es.lastEventId); | |
| // Periodically send messages | |
| var loop = setInterval(function() { es.send('Hello') }, 1000); | |
| es.on('close', function() { | |
| clearInterval(loop); | |
| es = null; | |
| }); | |
| } else { | |
| // Normal HTTP request | |
| response.writeHead(200, { 'Content-Type': 'text/plain' }); | |
| response.end('Hello'); | |
| } | |
| }); | |
| server.listen(8000); | |
| ``` | |
| The `send` method takes two optional parameters, `event` and `id`. The default | |
| event-type is `'message'` with no ID. For example, to send a `notification` | |
| event with ID `99`: | |
| ```js | |
| es.send('Breaking News!', { event: 'notification', id: '99' }); | |
| ``` | |
| The `EventSource` object exposes the following properties: | |
| - **`url`** is a string containing the URL the client used to create the | |
| EventSource. | |
| - **`lastEventId`** is a string containing the last event ID received by the | |
| client. You can use this when the client reconnects after a dropped connection | |
| to determine which messages need resending. | |
| When you initialize an EventSource with ` new EventSource()`, you can pass | |
| configuration options after the `response` parameter. Available options are: | |
| - **`headers`** is an object containing custom headers to be set on the | |
| EventSource response. | |
| - **`retry`** is a number that tells the client how long (in seconds) it should | |
| wait after a dropped connection before attempting to reconnect. | |
| - **`ping`** is a number that tells the server how often (in seconds) to send | |
| 'ping' packets to the client to keep the connection open, to defeat timeouts | |
| set by proxies. The client will ignore these messages. | |
| For example, this creates a connection that allows access from any origin, pings | |
| every 15 seconds and is retryable every 10 seconds if the connection is broken: | |
| ```js | |
| var es = new EventSource(request, response, { | |
| headers: { 'Access-Control-Allow-Origin': '*' }, | |
| ping: 15, | |
| retry: 10 | |
| }); | |
| ``` | |
| You can send a ping message at any time by calling `es.ping()`. Unlike | |
| WebSocket, the client does not send a response to this; it is merely to send | |
| some data over the wire to keep the connection alive. | |