1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
---
title: Написание клиентских приложений с помощью вебсокетов
slug: WebSockets/Writing_WebSocket_client_applications
translation_of: Web/API/WebSockets_API/Writing_WebSocket_client_applications
---
<p>{{ draft() }}</p>
<p>Вебсокеты - технология, которя позволяет открыть интерактивную сессию общения между браузером пользователя и сервером. Соединяясь через вебсокеты, веб-приложения могут осуществлять взаимодействие в реальном времени вместо того, чтобы делать запросы к клиенту о входящих/исходящих изменениях.</p>
<div class="note"><strong>Замечание: </strong>У нас есть работающий пример чата, части кода из которого используются в статье. Пример будет доступен, когда инфраструктура сайта сможет должным образом поддерживать хостинг примеров с использованием вебсокетов.</div>
<h2 id="Доступность_вебсокетов">Доступность вебсокетов</h2>
<p>API вебсокетов доступно в Javascript коде, область видимости которого включает объект DOM {{ domxref("Window") }} или любой объект, реализующий {{ domxref("WorkerUtils") }}; это означает, что вы можете использовать Web Workers.</p>
<div class="note"><strong>Замечание:</strong> API вебсокетов (как и протокол лежащий в его основе) всё ещё проходят этап активной разработки; в настоящее время существует много проблем совместимости с разными браузерами (и даже с разными релизами одного и того же браузера).</div>
<h2 id="Создание_объекта_WebSocket">Создание объекта WebSocket</h2>
<p><code><font face="Lucida Grande, Lucida Sans Unicode, DejaVu Sans, Lucida, Arial, Helvetica, sans-serif">Чтобы общаться через протокол вебсокетов необходимо создать объект </font><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="en/WebSockets/WebSockets reference/WebSocket">WebSocket</a></code>; при его создании автоматически происходит попытка открыть соединение с сервером.</p>
<p>Конструктор WebSocket принимает один обязательный и один необязательный параметр:</p>
<pre>WebSocket WebSocket(
in DOMString url,
in optional DOMString protocols
);
WebSocket WebSocket(
in DOMString url,
in optional DOMString[] protocols
);
</pre>
<dl>
<dt><code>url</code></dt>
<dd>URL, с которым происходит соединение; это должен быть URL вебсокет-сервера.</dd>
<dt><code>protocols</code> {{ optional_inline() }}</dt>
<dd>Может быть одной строкой протокола или массивом таких строк. Эти строки используют для индикации под-протоколов; таким образом, один сервер может реализовывать несколько под-протоколов вебсокетов (к примеру, вам может потребоваться, чтобы сервер мог обрабатывать разные типы взаимодействий в зависимости от определённого под-протокола). Если вы не укажете строку протокола, то будет передана пустая строка.</dd>
</dl>
<p>В конструкторе могут возникать следующие исключения:</p>
<dl>
<dt><code>SECURITY_ERR</code></dt>
<dd>Порт, к которому проводится подключение, заблокирован.</dd>
</dl>
<dl>
</dl>
<h3 id="Ошибки_подключения">Ошибки подключения</h3>
<p><span style="line-height: 21px;">Если ошибка случается во время попытки подключения, то в объект </span><a href="https://developer.mozilla.org/en/WebSockets/WebSockets_reference/WebSocket" style="line-height: 21px;" title="WebSocket"><code style="font-style: inherit;">WebSocket</code></a><span style="line-height: 21px;"> сначала посылается простое событие с именем «error» (таким образом, задействуя обработчик </span><code style="font-size: 14px; line-height: 21px;">onerror</code><span style="line-height: 21px;">), потом - событие </span><a href="https://developer.mozilla.org/en/WebSockets/WebSockets_reference/CloseEvent" style="line-height: 21px;" title="CloseEvent"><code style="font-style: inherit;">CloseEvent</code></a><span style="line-height: 21px;"> </span><span style="line-height: 21px;"> (таким образом, задействуя обработчик </span><code style="font-size: 14px; line-height: 21px;">onclose</code><span style="line-height: 21px;">) чтобы обозначить причину закрытия соединения.</span></p>
<p>Однако, начиная с версии Firefox 11, типичным является получение в консоль от платформы Mozilla расширенного сообщения об обшибке и кода завершения, как то определено в <a class="external" href="http://tools.ietf.org/html/rfc6455#section-7.4" title="RFC 6455 Section 7.4">RFC 6455, Section 7.4</a> посредством <a href="/en/WebSockets/WebSockets_reference/CloseEvent" title="CloseEvent"><code>CloseEvent</code></a>.</p>
<h3 id="Примеры">Примеры</h3>
<p>Этот простой пример создает новый WebSocket, подключаемый к серверу <code><span class="nowiki">ws://www.example.com/socketserver</span></code>. В данном примере в конструктор сокета в качестве дополнительного параметра передается пользовательский протокол "protocolOne", хотя эта часть может быть опущена.</p>
<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
</pre>
<p>После выполнения функции, <code>exampleSocket</code>.<code>readyState</code> будет иметь значение <code>CONNECTING</code>. <code>readyState</code> изменится на <code>OPEN</code> как только соединение станет готовым к передаче данных.</p>
<p>Если нужно открыть соединение, поддерживающее несколько протоколов, можно передать массив протоколов:</p>
<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]);
</pre>
<p>Когда соединение установлено (что соответствует, <code>readyState</code> <code>OPEN</code>), <code>exampleSocket.protocol</code> сообщит, какой протокол выбрал сервер.</p>
<p>In the above examples <code>ws</code> has replaced <code>http</code>, similarly <code>wss</code> replaces <code>https</code>. Establishing a WebSocket relies on the HTTP Upgrade mechanism, so the request for the protocol upgrade is implicit when we address the HTTP server as <code><span class="nowiki">ws://www.example.com</span></code> or <code><span class="nowiki">wss://www.example.com</span></code>.</p>
<h2 id="Отправка_данных_на_сервер">Отправка данных на сервер</h2>
<p>Однажды открыв соединение, вы можете передавать данные на сервер. Для осуществления этого, вызовите метод <a href="/en/WebSockets/WebSockets_reference/WebSocket#send()" title="en/WebSockets/WebSockets reference/WebSocket#send()"><code>send()</code></a> объекта <code>WebSocket</code> для каждого сообщение, которое желаете отправить:</p>
<pre class="brush: js">exampleSocket.send("Here's some text that the server is urgently awaiting!");
</pre>
<p>Вы можете пересылать данные в виде строки, {{ domxref("Blob") }}, так и <a href="/en/JavaScript_typed_arrays/ArrayBuffer" title="en/JavaScript typed arrays/ArrayBuffer"><code>ArrayBuffer</code></a>.</p>
<div class="note"><strong>Note:</strong> Prior to version 11, Firefox only supported sending data as a string.</div>
<p>As establishing a connection is asynchronous and prone to failure there is no guarantee that calling the <code>send()</code> method immediately after creating a WebSocket object will be successful. We can at least be sure that attempting to send data only takes place once a connection is established by defining an <code>onopen</code> handler to do the work:</p>
<pre class="brush: js">exampleSocket.onopen = function (event) {
exampleSocket.send("Here's some text that the server is urgently awaiting!");
};
</pre>
<h3 id="Using_JSON_to_transmit_objects">Using JSON to transmit objects</h3>
<p>One handy thing you can do is use <a href="/en/JSON" title="en/JSON">JSON</a> to send reasonably complex data to the server. For example, a chat program can interact with a server using a protocol implemented using packets of JSON-encapsulated data:</p>
<pre class="brush: js">// Send text to all users through the server
function sendText() {
// Construct a msg object containing the data the server needs to process the message from the chat client.
var msg = {
type: "message",
text: document.getElementById("text").value,
id: clientID,
date: Date.now()
};
// Send the msg object as a JSON-formatted string.
exampleSocket.send(JSON.stringify(msg));
// Blank the text input element, ready to receive the next line of text from the user.
document.getElementById("text").value = "";
}
</pre>
<h2 id="Receiving_messages_from_the_server">Receiving messages from the server</h2>
<p>WebSockets is an event-driven API; when messages are received, a "message" event is delivered to the <code>onmessage</code> function. To begin listening for incoming data, you can do something like this:</p>
<pre class="brush: js">exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</pre>
<h3 id="Receiving_and_interpreting_JSON_objects">Receiving and interpreting JSON objects</h3>
<p>Let's consider the chat client application first alluded to in {{ anch("Using JSON to transmit objects") }}. There are assorted types of data packets the client might receive, such as:</p>
<ul>
<li>Login handshake</li>
<li>Message text</li>
<li>User list updates</li>
</ul>
<p>The code that interprets these incoming messages might look like this:</p>
<pre class="brush: js">exampleSocket.onmessage = function(event) {
var f = document.getElementById("chatbox").contentDocument;
var text = "";
var msg = JSON.parse(event.data);
var time = new Date(msg.date);
var timeStr = time.toLocaleTimeString();
switch(msg.type) {
case "id":
clientID = msg.id;
setUsername();
break;
case "username":
text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>";
break;
case "message":
text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>";
break;
case "rejectusername":
text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>"
break;
case "userlist":
var ul = "";
for (i=0; i < msg.users.length; i++) {
ul += msg.users[i] + "<br>";
}
document.getElementById("userlistbox").innerHTML = ul;
break;
}
if (text.length) {
f.write(text);
document.getElementById("chatbox").contentWindow.scrollByPages(1);
}
};
</pre>
<p>Here we use <a href="/en/JavaScript/Reference/Global_Objects/JSON/parse" title="en/JavaScript/Reference/Global Objects/JSON/parse"><code>JSON.parse()</code></a> to convert the JSON object back into the original object, then examine and act upon its contents.</p>
<h3 id="Text_data_format">Text data format</h3>
<p>Text received over a WebSocket connection is in UTF-8 format.</p>
<p>Prior to Gecko 9.0 {{ geckoRelease("9.0") }}, certain non-characters in otherwise valid UTF-8 text would cause the connection to be terminated. Now Gecko permits these values.</p>
<h2 id="Closing_the_connection">Closing the connection</h2>
<p>When you've finished using the WebSocket connection, call the WebSocket method <a href="/en/WebSockets/WebSockets_reference/WebSocket#close()" title="en/WebSockets/WebSockets reference/WebSocket#close()"><code>close()</code></a>:</p>
<pre class="brush: js">exampleSocket.close();
</pre>
<p>It may be helpful to examine the socket's <code>bufferedAmount</code> attribute before attempting to close the connection to determine if any data has yet to be transmitted on the network.</p>
<h2 id="Security_considerations">Security considerations</h2>
<p>WebSockets should not be used in a mixed content environment; that is, you shouldn't open a non-secure WebSocket connection from a page loaded using HTTPS or vice-versa. In fact, some browsers explicitly forbid this, including Firefox 8 and later.</p>
<p>{{ languages ( {"zh-tw": "zh_tw/WebSockets/Writing_WebSocket_client_applications"} ) }}</p>
|