fixes
This commit is contained in:
parent
4f2a90854d
commit
1191dbb395
2 changed files with 34 additions and 31 deletions
|
@ -71,9 +71,9 @@ Now let's talk more in-depth.
|
|||
|
||||
## Opening a websocket
|
||||
|
||||
When `new WebSocket(url)` is created, it starts an HTTP handshake (HTTPS for `wss://`).
|
||||
When `new WebSocket(url)` is created, it starts connecting immediately.
|
||||
|
||||
The browser asks the server: "Do you support Websocket?" And if the server says "yes", then the talk continues in WebSocket protocol, which is not HTTP at all.
|
||||
During the connection the browser (using headers) asks the server: "Do you support Websocket?" And if the server replies "yes", then the talk continues in WebSocket protocol, which is not HTTP at all.
|
||||
|
||||

|
||||
|
||||
|
@ -89,7 +89,7 @@ Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
|
|||
Sec-WebSocket-Version: 13
|
||||
```
|
||||
|
||||
- `Origin` -- the origin of the client page. WebSocket is cross-origin by nature. There are no special headers or other limitations. Old servers are unable to handle WebSocket anyway, so there are no compabitility issues. But `Origin` header is important, as it allows the server to decide whether or not to talk WebSocket with this website.
|
||||
- `Origin` -- the origin of the client page, e.g. `https://javascript.info`. WebSocket objects are cross-origin by nature. There are no special headers or other limitations. Old servers are unable to handle WebSocket anyway, so there are no compabitility issues. But `Origin` header is important, as it allows the server to decide whether or not to talk WebSocket with this website.
|
||||
- `Connection: Upgrade` -- signals that the client would like to change the protocol.
|
||||
- `Upgrade: websocket` -- the requested protocol is "websocket".
|
||||
- `Sec-WebSocket-Key` -- a random browser-generated key for security.
|
||||
|
@ -120,11 +120,11 @@ For instance:
|
|||
|
||||
- `Sec-WebSocket-Extensions: deflate-frame` means that the browser supports data compression. An extension is something related to transferring the data, not data itself.
|
||||
|
||||
- `Sec-WebSocket-Protocol: soap, wamp` means that we're going to transfer not just any data, but the data in [SOAP](http://en.wikipedia.org/wiki/SOAP) or WAMP ("The WebSocket Application Messaging Protocol") protocols. WebSocket subprotocols are registered in the [IANA catalogue](http://www.iana.org/assignments/websocket/websocket.xml).
|
||||
- `Sec-WebSocket-Protocol: soap, wamp` means that we'd like to transfer not just any data, but the data in [SOAP](http://en.wikipedia.org/wiki/SOAP) or WAMP ("The WebSocket Application Messaging Protocol") protocols. WebSocket subprotocols are registered in the [IANA catalogue](http://www.iana.org/assignments/websocket/websocket.xml).
|
||||
|
||||
`Sec-WebSocket-Extensions` is sent by the browser automatically, with a list of possible extensions it supports.
|
||||
`Sec-WebSocket-Extensions` header is sent by the browser automatically, with a list of possible extensions it supports.
|
||||
|
||||
`Sec-WebSocket-Protocol` depends on us: we decide what kind of data we send. The second optional parameter of `new WebSocket` lists subprotocols:
|
||||
`Sec-WebSocket-Protocol` header depends on us: we decide what kind of data we send. The second optional parameter of `new WebSocket` is just for that, it lists subprotocols:
|
||||
|
||||
```js
|
||||
let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
|
||||
|
@ -161,24 +161,24 @@ Sec-WebSocket-Protocol: soap
|
|||
*/!*
|
||||
```
|
||||
|
||||
Here the server responds that it supports the extension `deflate-frame`, and only SOAP of the requested subprotocols.
|
||||
Here the server responds that it supports the extension "deflate-frame", and only SOAP of the requested subprotocols.
|
||||
|
||||
## WebSocket data
|
||||
|
||||
WebSocket communication consists of "frames" that can be sent from either side:
|
||||
WebSocket communication consists of "frames" -- data fragments, that can be sent from either side, and can be of several kinds:
|
||||
|
||||
- "text frames" -- contain text data that parties send to each other.
|
||||
- "binary data frames" -- contain binary data that parties send to each other.
|
||||
- "ping/pong frames" are used to check the connection, sent from the server, the browser responds to these automatically.
|
||||
- "connection close frame" and a few other service frames.
|
||||
|
||||
In the browser, we only care about text or binary frames.
|
||||
In the browser, we directly work only with text or binary frames.
|
||||
|
||||
**WebSocket `.send()` can send either text or binary data, doesn't matter.**
|
||||
**WebSocket `.send()` method can send either text or binary data.**
|
||||
|
||||
For sending, `socket.send(body)` allows strings or any binary format, including `Blob`, `ArrayBuffer`, etc. No settings required: just send it out.
|
||||
A call `socket.send(body)` allows `body` in string or a binary format, including `Blob`, `ArrayBuffer`, etc. No settings required: just send it out.
|
||||
|
||||
**Textual data always comes as string. For receiving binary data, we can choose between `Blob` and `ArrayBuffer` formats.**
|
||||
**When we receive the data, text always comes as string. And for binary data, we can choose between `Blob` and `ArrayBuffer` formats.**
|
||||
|
||||
The `socket.bufferType` is `"blob"` by default, so binary data comes in Blobs.
|
||||
|
||||
|
@ -193,16 +193,17 @@ socket.onmessage = (event) => {
|
|||
|
||||
## Rate limiting
|
||||
|
||||
Imagine, our app is generating a lot of data to send. But network connection is not that fast. The user may be on a mobile, in rural area.
|
||||
Imagine, our app is generating a lot of data to send. But the user has a slow network connection, maybe on a mobile, outside of a city.
|
||||
|
||||
We can call `socket.send(data)` again and again. But the data will be buffered in memory and sent out only as fast as network speed allows.
|
||||
We can call `socket.send(data)` again and again. But the data will be buffered (stored) in memory and sent out only as fast as network speed allows.
|
||||
|
||||
The `socket.bufferedAmount` property stores how many bytes are buffered at this moment, waiting to be sent over the network.
|
||||
|
||||
We can examine it to see whether the socket is actually available for transmission.
|
||||
|
||||
```js
|
||||
// every 100ms examine the socket and send more data only if no data buffered
|
||||
// every 100ms examine the socket and send more data
|
||||
// only if all the existing data was sent out
|
||||
setInterval(() => {
|
||||
if (socket.bufferedAmount == 0) {
|
||||
socket.send(moreData());
|
||||
|
@ -215,18 +216,21 @@ setInterval(() => {
|
|||
|
||||
Normally, when a party wants to close the connection (both browser and server have equal rights), they send a "connection close frame" with a numeric code and a textual reason.
|
||||
|
||||
The method is:
|
||||
The method for that is:
|
||||
```js
|
||||
socket.close([code], [reason]);
|
||||
```
|
||||
|
||||
Then the other party in `close` event handle can get the code and the reason, e.g.:
|
||||
- `code` is a special WebSocket closing code (optional)
|
||||
- `reason` is a string that describes the reason of closing (optional)
|
||||
|
||||
Then the other party in `close` event handler gets the code and the reason, e.g.:
|
||||
|
||||
```js
|
||||
// one party:
|
||||
// closing party:
|
||||
socket.close(1000, "Work complete");
|
||||
|
||||
// another party
|
||||
// the other party
|
||||
socket.onclose = event => {
|
||||
// event.code === 1000
|
||||
// event.reason === "Work complete"
|
||||
|
@ -234,12 +238,10 @@ socket.onclose = event => {
|
|||
};
|
||||
```
|
||||
|
||||
The `code` is not just any number, but a special WebSocket closing code.
|
||||
Most common code values:
|
||||
|
||||
Most common values:
|
||||
|
||||
- `1000` -- the default, normal closure,
|
||||
- `1006` -- can't set such code manually, indicates that the connection was broken (no close frame).
|
||||
- `1000` -- the default, normal closure (used if no `code` supplied),
|
||||
- `1006` -- no way to such code manually, indicates that the connection was lost (no close frame).
|
||||
|
||||
There are other codes like:
|
||||
|
||||
|
@ -316,9 +318,9 @@ Server-side code is a little bit beyond our scope here. We're using browser WebS
|
|||
|
||||
Still it can also be pretty simple. We'll use Node.js with <https://github.com/websockets/ws> module for websockets.
|
||||
|
||||
The algorithm will be:
|
||||
The server-side algorithm will be:
|
||||
1. Create `clients = new Set()` -- a set of sockets.
|
||||
2. For each accepted websocket, `clients.add(socket)` and listen for its messages.
|
||||
2. For each accepted websocket, `clients.add(socket)` and add `onmessage` listener for its messages.
|
||||
3. When a message received: iterate over clients and send it to everyone.
|
||||
4. When a connection is closed: `clients.delete(socket)`.
|
||||
|
||||
|
@ -329,7 +331,8 @@ const wss = new ws.Server({noServer: true});
|
|||
const clients = new Set();
|
||||
|
||||
http.createServer((req, res) => {
|
||||
// in real project we have additional code here to handle non-websocket requests
|
||||
// here we only handle websocket connections
|
||||
// in real project we'd have some other code herre to handle non-websocket requests
|
||||
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
|
||||
});
|
||||
|
||||
|
@ -378,8 +381,8 @@ Events:
|
|||
- `error`,
|
||||
- `close`.
|
||||
|
||||
WebSocket by itself does not include reconnection, authentication and many other high-level mechanisms. So there are client/server libraries that add them. But it's also possible to implement these manually and integrate WebSockets with an existing site.
|
||||
WebSocket by itself does not include reconnection, authentication and many other high-level mechanisms. So there are client/server libraries for that, and it's also possible to implement these capabilities manually.
|
||||
|
||||
For integration purposes, a WebSocket server is usually running in parallel with the main server, and they share a single database. Requests to WebSocket use `wss://ws.site.com`, a subdomain that leads to WebSocket server, while `https://site.com` goes to the main HTTP-server.
|
||||
Sometimes, to integrate WebSocket into existing project, people run WebSocket server in parallel with the main HTTP-server, and they share a single database. Requests to WebSocket use `wss://ws.site.com`, a subdomain that leads to WebSocket server, while `https://site.com` goes to the main HTTP-server.
|
||||
|
||||
Surely, other ways of integration are also possible. Many servers (such as Node.js) can support both HTTP and WebSocket protocols.
|
||||
|
|
|
@ -111,7 +111,7 @@ Regexp "open HTML-tag without attributes", like `<span>` or `<p>`: `pattern:/<[a
|
|||
alert( "<body> ... </body>".match(/<[a-z]+>/gi) ); // <body>
|
||||
```
|
||||
|
||||
We look for character `pattern:'<'` followed by one or more English letters, and then `pattern:'>'`.
|
||||
We look for character `pattern:'<'` followed by one or more Latin letters, and then `pattern:'>'`.
|
||||
|
||||
Regexp "open HTML-tag without attributes" (improved): `pattern:/<[a-z][a-z0-9]*>/i`
|
||||
: Better regexp: according to the standard, HTML tag name may have a digit at any position except the first one, like `<h1>`.
|
||||
|
@ -132,7 +132,7 @@ We can see one common rule in these examples: the more precise is the regular ex
|
|||
|
||||
For instance, for HTML tags we could use a simpler regexp: `pattern:<\w+>`.
|
||||
|
||||
...But because `pattern:\w` means any English letter or a digit or `'_'`, the regexp also matches non-tags, for instance `match:<_>`. So it's much simpler than `pattern:<[a-z][a-z0-9]*>`, but less reliable.
|
||||
...But because `pattern:\w` means any Latin letter or a digit or `'_'`, the regexp also matches non-tags, for instance `match:<_>`. So it's much simpler than `pattern:<[a-z][a-z0-9]*>`, but less reliable.
|
||||
|
||||
Are we ok with `pattern:<\w+>` or we need `pattern:<[a-z][a-z0-9]*>`?
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue