Содержание
- Listening to events
- EventEmitter methods
- socket.on(eventName, listener)
- socket.once(eventName, listener)
- socket.off(eventName, listener)
- socket.removeAllListeners( [eventName] )
- Catch-all listeners
- socket.onAny(listener)
- socket.prependAny(listener)
- socket.offAny( [listener] )
- Validation
- Client API
- io.protocol
- io( [url][, options] )
- Manager
- new Manager(url [, options] )
- manager.reconnection( [value] )
- manager.reconnectionAttempts( [value] )
- manager.reconnectionDelay( [value] )
- Client API
- io.protocol
- io( [url][, options] )
- Manager
- Constructor
- new Manager(url [, options] )
- Events
- Event: ‘error’
- Event: ‘ping’
- Event: ‘reconnect’
- Event: ‘reconnect_attempt’
- Event: ‘reconnect_error’
- Event: ‘reconnect_failed’
- Methods
- manager.connect( [callback] )
- manager.open( [callback] )
- manager.reconnection( [value] )
- manager.reconnectionAttempts( [value] )
- manager.reconnectionDelay( [value] )
- manager.reconnectionDelayMax( [value] )
- manager.socket(nsp, options)
- manager.timeout( [value] )
- Socket
- Events
- Event: ‘connect’
- Event: ‘disconnect’
- Event: ‘connect_error’
Listening to events
There are several ways to handle events that are transmitted between the server and the client.
EventEmitter methods
On the server-side, the Socket instance extends the Node.js EventEmitter class.
On the client-side, the Socket instance uses the event emitter provided by the component-emitter library, which exposes a subset of the EventEmitter methods.
socket.on(eventName, listener)
Adds the listener function to the end of the listeners array for the event named eventName.
socket.once(eventName, listener)
Adds a one-time listener function for the event named eventName
socket.off(eventName, listener)
Removes the specified listener from the listener array for the event named eventName.
socket.removeAllListeners( [eventName] )
Removes all listeners, or those of the specified eventName.
Catch-all listeners
Since Socket.IO v3, a new API inspired from the EventEmitter2 library allows to declare catch-all listeners.
This feature is available on both the client and the server.
socket.onAny(listener)
Adds a listener that will be fired when any event is emitted.
socket.prependAny(listener)
Adds a listener that will be fired when any event is emitted. The listener is added to the beginning of the listeners array.
socket.offAny( [listener] )
Removes all catch-all listeners, or the given listener.
Validation
The validation of the event arguments is out of the scope of the Socket.IO library.
There are many packages in the JS ecosystem which cover this use case, among them:
Источник
Client API
Exposed as the io namespace in the standalone build, or the result of calling require(«socket.io-client») .
io.protocol
The protocol revision number (currently: 5).
The protocol defines the format of the packets exchanged between the client and the server. Both the client and the server must use the same revision in order to understand each other.
You can find more information here.
io( [url][, options] )
- url (String) (defaults to window.location.host )
- options (Object)
- forceNew (Boolean) whether to reuse an existing connection
- Returns Socket
Creates a new Manager for the given URL, and attempts to reuse an existing Manager for subsequent calls, unless the multiplex option is passed with false . Passing this option is the equivalent of passing «force new connection»: true or forceNew: true .
A new Socket instance is returned for the namespace specified by the pathname in the URL, defaulting to / . For example, if the url is http://localhost/users , a transport connection will be established to http://localhost and a Socket.IO connection will be established to /users .
Query parameters can also be provided, either with the query option or directly in the url (example: http://localhost/users?token=abc ).
is the short version of:
See new Manager(url[, options]) for the list of available options .
Please note: manager.socket(«/my-namespace», options ) will only read the auth key in the options object. query: <…>and other optional values are only used when passed via a new Manager(uri, options) instance.
See Migrating from 2.x to 3.0 for more on the difference between the auth and query options.
Manager
The Manager manages the Engine.IO client instance, which is the low-level engine that establishes the connection to the server (by using transports like WebSocket or HTTP long-polling).
The Manager handles the reconnection logic.
A single Manager can be used by several Sockets. You can find more information about this multiplexing feature here.
Please note that, in most cases, you won’t use the Manager directly but use the Socket instance instead.
new Manager(url [, options] )
- url (String)
- options (Object)
- Returns Manager
Option | Default value | Description | ||
---|---|---|---|---|
path | /socket.io | name of the path that is captured on the server side | ||
reconnection | true | whether to reconnect automatically | ||
reconnectionAttempts | Infinity | number of reconnection attempts before giving up | ||
reconnectionDelay | 1000 | how long to initially wait before attempting a new reconnection. Affected by +/- randomizationFactor , for example the default initial delay will be between 500 to 1500ms. | ||
reconnectionDelayMax | 5000 | maximum amount of time to wait between reconnections. Each attempt increases the reconnection delay by 2x along with a randomization factor. | ||
randomizationFactor | 0.5 | 0 timeout | 20000 | connection timeout before an error event is emitted |
autoConnect | true | by setting this false, you have to call manager.open whenever you decide it’s appropriate | ||
query | <> | additional query parameters that are sent when connecting a namespace (then found in socket.handshake.query object on the server-side) | ||
parser | — | the parser to use. Defaults to an instance of the Parser that ships with socket.io. See socket.io-parser. |
Available options for the underlying Engine.IO client:
Option | Default value | Description |
---|---|---|
upgrade | true | whether the client should try to upgrade the transport from long-polling to something better. |
forceJSONP | false | forces JSONP for polling transport. |
jsonp | true | determines whether to use JSONP when necessary for polling. If disabled (by settings to false) an error will be emitted (saying «No transports available») if no other transports are available. If another transport is available for opening a connection (e.g. WebSocket) that transport will be used instead. |
forceBase64 | false | forces base 64 encoding for polling transport even when XHR2 responseType is available and WebSocket even if the used standard supports binary. |
enablesXDR | false | enables XDomainRequest for IE8 to avoid loading bar flashing with click sound. default to false because XDomainRequest has a flaw of not sending cookie. |
timestampRequests | — | whether to add the timestamp with each transport request. Note: polling requests are always stamped unless this option is explicitly set to false |
timestampParam | t | the timestamp parameter |
transports | [«polling», «websocket»] | a list of transports to try (in order). Engine always attempts to connect directly with the first one, provided the feature detection test for it passes. |
transportOptions | <> | hash of options, indexed by transport name, overriding the common options for the given transport |
rememberUpgrade | false | If true and if the previous websocket connection to the server succeeded, the connection attempt will bypass the normal upgrade process and will initially try websocket. A connection attempt following a transport error will use the normal upgrade process. It is recommended you turn this on only when using SSL/TLS connections, or if you know that your network does not block websockets. |
onlyBinaryUpgrades | false | whether transport upgrades should be restricted to transports supporting binary data |
requestTimeout | timeout for xhr-polling requests in milliseconds ( 0 ) (only for polling transport) | |
protocols | — | a list of subprotocols (see MDN reference) (only for websocket transport) |
Node.js-only options for the underlying Engine.IO client:
Option | Default value | Description |
---|---|---|
agent | false | the http.Agent to use |
pfx | — | Certificate, Private key and CA certificates to use for SSL. |
key | — | Private key to use for SSL. |
passphrase | — | A string of passphrase for the private key or pfx. |
cert | — | Public x509 certificate to use. |
ca | — | An authority certificate or array of authority certificates to check the remote host against. |
ciphers | — | A string describing the ciphers to use or exclude. Consult the cipher format list for details on the format. |
rejectUnauthorized | true | If true, the server certificate is verified against the list of supplied CAs. An «error» event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. |
perMessageDeflate | true | parameters of the WebSocket permessage-deflate extension (see ws module api docs). Set to false to disable. |
extraHeaders | <> | Headers that will be passed for each request to the server (via xhr-polling and via websockets). These values then can be used during handshake or for special proxies. |
forceNode | false | Uses NodeJS implementation for websockets — even if there is a native Browser-Websocket available, which is preferred by default over the NodeJS implementation. (This is useful when using hybrid platforms like nw.js or electron) |
localAddress | — | the local IP address to connect to |
manager.reconnection( [value] )
- value (Boolean)
- Returns Manager|Boolean
Sets the reconnection option, or returns it if no parameters are passed.
manager.reconnectionAttempts( [value] )
- value (Number)
- Returns Manager|Number
Sets the reconnectionAttempts option, or returns it if no parameters are passed.
manager.reconnectionDelay( [value] )
- value (Number)
- Returns Manager|Number
Sets the reconnectionDelay option, or returns it if no parameters are passed.
Источник
Client API
The io method is bound to the global scope in the standalone build:
An ESM bundle is also available since version 4.3.0:
Else, in all other cases (with some build tools, in Node.js or React Native), it can be imported from the socket.io-client package:
io.protocol
The protocol revision number (currently: 5).
The protocol defines the format of the packets exchanged between the client and the server. Both the client and the server must use the same revision in order to understand each other.
You can find more information here.
io( [url][, options] )
- url (defaults to window.location.host )
- options
- forceNew whether to create a new connection
- Returns
Creates a new Manager for the given URL, and attempts to reuse an existing Manager for subsequent calls, unless the multiplex option is passed with false . Passing this option is the equivalent of passing «force new connection»: true or forceNew: true .
A new Socket instance is returned for the namespace specified by the pathname in the URL, defaulting to / . For example, if the url is http://localhost/users , a transport connection will be established to http://localhost and a Socket.IO connection will be established to /users .
Query parameters can also be provided, either with the query option or directly in the url (example: http://localhost/users?token=abc ).
To understand what happens under the hood, the following example:
is the short version of:
The complete list of available options can be found here.
Manager
The Manager manages the Engine.IO client instance, which is the low-level engine that establishes the connection to the server (by using transports like WebSocket or HTTP long-polling).
The Manager handles the reconnection logic.
A single Manager can be used by several Sockets. You can find more information about this multiplexing feature here.
Please note that, in most cases, you won’t use the Manager directly but use the Socket instance instead.
Constructor
new Manager(url [, options] )
- url
- options
- Returns
The complete list of available options can be found here.
Events
Event: ‘error’
Fired upon a connection error.
Event: ‘ping’
Fired when a ping packet is received from the server.
Event: ‘reconnect’
- attempt reconnection attempt number
Fired upon a successful reconnection.
Event: ‘reconnect_attempt’
- attempt reconnection attempt number
Fired upon an attempt to reconnect.
Event: ‘reconnect_error’
Fired upon a reconnection attempt error.
Event: ‘reconnect_failed’
Fired when couldn’t reconnect within reconnectionAttempts .
Methods
manager.connect( [callback] )
manager.open( [callback] )
- callback
- Returns
If the manager was initiated with autoConnect to false , launch a new connection attempt.
The callback argument is optional and will be called once the attempt fails/succeeds.
manager.reconnection( [value] )
Sets the reconnection option, or returns it if no parameters are passed.
manager.reconnectionAttempts( [value] )
Sets the reconnectionAttempts option, or returns it if no parameters are passed.
manager.reconnectionDelay( [value] )
Sets the reconnectionDelay option, or returns it if no parameters are passed.
manager.reconnectionDelayMax( [value] )
Sets the reconnectionDelayMax option, or returns it if no parameters are passed.
manager.socket(nsp, options)
- nsp
- options
- Returns
Creates a new Socket for the given namespace. Only auth ( < auth: > ) is read from the options object. Other keys will be ignored and should be passed when instancing a new Manager(nsp, options) .
manager.timeout( [value] )
Sets the timeout option, or returns it if no parameters are passed.
Socket
A Socket is the fundamental class for interacting with the server. A Socket belongs to a certain Namespace (by default / ) and uses an underlying Manager to communicate.
A Socket is basically an EventEmitter which sends events to — and receive events from — the server over the network.
More information can be found here.
Events
Event: ‘connect’
Fired upon connection to the Namespace (including a successful reconnection).
Please note that you shouldn’t register event handlers in the connect handler itself, as a new handler will be registered every time the Socket reconnects:
Event: ‘disconnect’
Fired upon disconnection. The list of possible disconnection reasons:
Reason | Description |
---|---|
io server disconnect | The server has forcefully disconnected the socket with socket.disconnect() |
io client disconnect | The socket was manually disconnected using socket.disconnect() |
ping timeout | The server did not send a PING within the pingInterval + pingTimeout range |
transport close | The connection was closed (example: the user has lost connection, or the network was changed from WiFi to 4G) |
transport error | The connection has encountered an error (example: the server was killed during a HTTP long-polling cycle) |
In the first two cases (explicit disconnection), the client will not try to reconnect and you need to manually call socket.connect() .
In all other cases, the client will wait for a small random delay and then try to reconnect:
Event: ‘connect_error’
Fired when a namespace middleware error occurs.
Источник
The 2.0.0
release is the first release which is compatible with the Socket.IO v3 server. You can find more information about the v3 release here: https://socket.io/blog/socket-io-3-release/
Here is the compatibility table:
Java client version | Socket.IO server |
---|---|
0.9.x | 1.x |
1.x | 2.x (or 3.1.x / 4.x with allowEIO3: true ) |
2.x | 3.x / 4.x |
Important note: due to the backward incompatible changes to the Socket.IO protocol, a 2.x Java client will not be able to reach a 2.x server, and vice-versa
Since the Java client matches the Javascript client quite closely, most of the changes listed in the migration guide here also apply to the Java client:
- A middleware error will now emit an Error object
- The Socket
query
option is renamed toauth
- The Socket instance will no longer forward the events emitted by its Manager
- No more “pong” event
Additional changes which are specific to the Java client:
- An
extraHeaders
option is now available
A middleware error will now emit an Error object
The ERROR
event is renamed to CONNECT_ERROR
and the object emitted is now a JSONObject
:
Before:
socket.on(Socket.EVENT_ERROR, new Emitter.Listener() { @Override public void call(Object... args) { String error = (String) args[0]; System.out.println(error); // not authorized } });
After:
socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { @Override public void call(Object... args) { JSONObject error = (JSONObject) args[0]; String message = error.getString("message"); System.out.println(error); // not authorized JSONObject data = error.getJSONObject("data"); // additional details (optional) } });
The Socket query
option is renamed to auth
In previous versions, the query
option was used in two distinct places:
- in the query parameters of the HTTP requests (
GET /socket.io/?EIO=3&abc=def
) - in the Socket.IO handshake
Which could lead to unexpected behaviors.
New syntax:
IO.Options options = new IO.Options(); options.query = singletonMap("abc", singletonList("def")); // included in the query parameters options.auth = singletonMap("token", singletonList("1234")); // included in the Socket.IO handshake Socket socket = IO.socket("https://example.com", options);
The Socket instance will no longer forward the events emitted by its Manager
In previous versions, the Socket instance emitted the events related to the state of the underlying connection. This will not be the case anymore.
You still have access to those events on the Manager instance (the io()
method of the socket) :
Before:
socket.on(Socket.EVENT_RECONNECT_ATTEMPT, new Emitter.Listener() { @Override public void call(Object... objects) { // ... } });
After:
socket.io().on(Manager.EVENT_RECONNECT_ATTEMPT, new Emitter.Listener() { @Override public void call(Object... objects) { // ... } });
Here is the updated list of events emitted by the Manager:
Name | Description | Previously (if different) |
---|---|---|
Manager.EVENT_OPEN |
successful (re)connection | — |
Manager.EVENT_ERROR |
(re)connection failure or error after a successful connection | Manager.EVENT_CONNECT_ERROR & Manager.EVENT_CONNECT_TIMEOUT |
Manager.EVENT_CLOSE |
disconnection | — |
Manager.EVENT_RECONNECT_ATTEMPT |
reconnection attempt | Manager.EVENT_RECONNECT_ATTEMPT & Manager.EVENT_RECONNECTING (duplicate) |
Manager.EVENT_RECONNECT |
successful reconnection | — |
Manager.EVENT_RECONNECT_ERROR |
reconnection failure | — |
Manager.EVENT_RECONNECT_FAILED |
reconnection failure after all attempts | — |
Here is the updated list of events emitted by the Socket:
Name | Description | Previously (if different) |
---|---|---|
Socket.EVENT_CONNECT |
successful connection to a Namespace | — |
Socket.EVENT_CONNECT_ERROR |
connection failure | Socket.EVENT_ERROR |
Socket.EVENT_DISCONNECT |
disconnection | — |
And finally, here’s the updated list of reserved events that you cannot use in your application:
connect
(used on the client-side)connect_error
(used on the client-side)disconnect
(used on both sides)disconnecting
(used on the server-side)newListener
andremoveListener
(EventEmitter reserved events)
socket.emit("connect_error"); // will now throw an exception
No more “pong” event
In Socket.IO v2, you could listen to the pong
event on the client-side, which included the duration of the last health check round-trip.
Due to the reversal of the heartbeat mechanism (more information here), this event has been removed.
Before:
socket.once(Socket.EVENT_PONG, new Emitter.Listener() { @Override public void call(Object... args) { long latency = (long) args[0]; // ... } });
There is no similar API in the new release.
An extraHeaders
option is now available
This is a more straightforward way to provide headers that will be included in all HTTP requests.
IO.Options options = new IO.Options(); options.extraHeaders = singletonMap("Authorization", singletonList("Bearer abcd")); Socket socket = IO.socket("https://example.com", options);
Or with the new builder syntax:
IO.Options options = IO.Options.builder() .setExtraHeaders(singletonMap("Authorization", singletonList("Bearer abcd"))) .build(); Socket socket = IO.socket("https://example.com", options);
Прослушивание мероприятий
Существует несколько способов обработки событий,которые передаются между сервером и клиентом.
EventEmitter methods
На стороне сервера экземпляр Socket расширяет класс Node.js EventEmitter .
На стороне клиента экземпляр Socket использует эмиттер событий, предоставляемый библиотекой компонентов-эмиттеров , которая предоставляет подмножество методов EventEmitter.
socket.on(eventName, listener)
Добавляет функцию прослушивателя в конец массива слушателей для события с именем eventName .
socket.on("details", (...args) => { // ... });
socket.once(eventName, listener)
Добавляет одноразовую функцию прослушивания для события с именем eventName
socket.once("details", (...args) => { // ... });
socket.off(eventName, listener)
Удаляет указанный слушатель из массива слушателей для события с именем eventName .
const listener = (...args) => { console.log(args); } socket.on("details", listener); // and then later... socket.off("details", listener);
socket.removeAllListeners([eventName])
Удаляет всех слушателей или слушателей указанного eventName .
socket.removeAllListeners("details"); socket.removeAllListeners();
Catch-all listeners
Начиная с Socket.IO v3, новый API, вдохновленный библиотекой EventEmitter2, позволяет объявлять универсальных прослушивателей.
Эта функция доступна как на клиенте,так и на сервере.
socket.onAny(listener)
Добавляет слушателя,который будет запускаться при возникновении любого события.
socket.onAny((eventName, ...args) => { // ... });
socket.prependAny(listener)
Добавляет слушатель,который будет запускаться при возникновении любого события.Слушатель добавляется в начало массива слушателей.
socket.prependAny((eventName, ...args) => { // ... });
socket.offAny([listener])
Удаляет все прослушивающие устройства или указанное прослушивающее устройство.
const listener = (eventName, ...args) => { console.log(eventName, args); } socket.onAny(listener); socket.offAny(listener); socket.offAny();
Validation
Проверка аргументов события выходит за рамки библиотеки Socket.IO.
В экосистеме JS есть много пакетов,которые охватывают этот вариант использования,среди них:
- joi
- ajv
- validatorjs
Пример с joi и благодарностями :
const Joi = require("joi"); const userSchema = Joi.object({ username: Joi.string().max(30).required(), email: Joi.string().email().required() }); io.on("connection", (socket) => { socket.on("create user", (payload, callback) => { if (typeof callback !== "function") { return socket.disconnect(); } const { error, value } = userSchema.validate(payload); if (error) { return callback({ status: "KO", error }); } callback({ status: "OK" }); }); });
Error handling
В настоящее время в библиотеке Socket.IO нет встроенной обработки ошибок,что означает,что вы должны поймать любую ошибку,которая может быть брошена в слушателе.
io.on("connection", (socket) => { socket.on("list items", async (callback) => { try { const items = await findItems(); callback({ status: "OK", items }); } catch (e) { callback({ status: "NOK" }); } }); });
На стороне сервера использование EventEmitter.captureRejections = true
(экспериментальное, см. Здесь ) тоже может быть интересным, в зависимости от вашего варианта использования.
require("events").captureRejections = true; io.on("connection", (socket) => { socket.on("list products", async () => { const products = await findProducts(); socket.emit("products", products); }); socket[Symbol.for('nodejs.rejection')] = (err) => { socket.emit("error", err); }; });
Socket.IO
4.5
-
Handling CORS
-
Как это работает
-
Load testing
-
Logging and debugging