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: Web/API/WebSockets_API/Writing_WebSocket_client_applications
translation_of: Web/API/WebSockets_API/Writing_WebSocket_client_applications
original_slug: WebSockets/Writing_WebSocket_client_applications
---
<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>В приведенных выше примерах <code>ws</code> заменяет <code>http</code>, аналогично <code>wss</code> заменяет <code>https</code>. Установка соединения через WebSocket зависит от механизма обновления HTTP, таким образом запрос на обновление неявный, когда мы обращаемся к серверу HTTP с помощью <code><span class="nowiki">ws://www.example.com</span></code> или <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("Вот текст, который будет отправлен серверу.");
</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>Замечание:</strong> До версии 11, Firefox поддерживал отправку данных только в виде строки.</div>
<p>Так как установка соедиения асинхронна и подвержена сбоям, то нет никакой гарантии, что вызов метода <code>send()</code>, после создания объекта WebSocket, будет завершен успешно. По крайней мере, мы можем быть уверены, что попытка отправить данные будет иметь место только после того, как соединение будет установлено, определив обработчик <code>onopen</code> для выполнения этого действия:</p>
<pre class="brush: js">exampleSocket.onopen = function (event) {
exampleSocket.send("Вот текст, который будет отправлен серверу.");
};
</pre>
<h3 id="Использование_JSON_для_передачи_объектов">Использование JSON для передачи объектов</h3>
<p>Одна удобная вещь которую вы можете сделать, это использовать <a href="/en/JSON" title="en/JSON">JSON</a> для пересылки сложных данных на сервер. Например, приложение-чат может взаимодействовать с сервером, используя протокол, реализованный с использованием пакетов данных, инкапсулированных в JSON:</p>
<pre class="brush: js">// Отправьте текст всем пользователям через сервер
function sendText() {
// Создайте объект содержащий данные, необходимые серверу для обрабоки сообщения от клиента чата.
var msg = {
type: "message",
text: document.getElementById("text").value,
id: clientID,
date: Date.now()
};
// Отправьте объект в виде JSON строки.
exampleSocket.send(JSON.stringify(msg));
// Очистите элемент ввода текста, чтобы получить следующую строку текста от пользователя.
document.getElementById("text").value = "";
}
</pre>
<h2 id="Получение_сообщений_от_сервера">Получение сообщений от сервера</h2>
<p>WebSockets — это API, управляемый событиями; когда сообщения получены, событие "message" доставлено в функцию <code>onmessage</code>. Чтобы начать прослушивание входящих данных, вы можете сделать что-то вроде этого:</p>
<pre class="brush: js">exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</pre>
<h3 id="Получение_и_интерпретация_JSON_объектов">Получение и интерпретация JSON объектов</h3>
<p>Давайте рассмотрим клиентское приложение чата, которое впервые упоминалось в разделе {{ anch("Использование JSON для передачи объектов") }}. Есть разные типы пакетов данных, которые может получить клиент, например:</p>
<ul>
<li>Вход в систему</li>
<li>Текст сообщения</li>
<li>Обновление списка пользователей</li>
</ul>
<p>Код обрабатывающий эти входящие сообщения, может выглядеть так:</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>Здесь мы используем <a href="/en/JavaScript/Reference/Global_Objects/JSON/parse" title="en/JavaScript/Reference/Global Objects/JSON/parse"><code>JSON.parse()</code></a> чтобы преобразовать JSON строку в объект, затем обработайте его.</p>
<h3 id="Формат_текстовых_данных">Формат текстовых данных</h3>
<p>Текст, полученный через WebSocket должен иметь кодировку UTF-8</p>
<p>До Gecko 9.0 {{ geckoRelease("9.0") }}, некоторые не символьные значения в допустимом тексте UTF-8 могут привести к разрыву соединения. Теперь Gecko допускает эти значения.</p>
<h2 id="Закрытие_соединения">Закрытие соединения</h2>
<p>Когда вы закончили использовать соединение WebSocket, закройте его используя метод <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>Перед попыткой закрыть соединение может быть полезно проверить атрибут <code>bufferedAmount</code> чтобы определить, не переданы ли еще какие-либо данные по сети.</p>
<h2 id="Безопасность">Безопасность</h2>
<p>WebSocket не следует использовать в среде со смешанным содержимым: то есть вы не должны открывать незащищенное соединение WebSocket со страницы, загруженной с использованием HTTPS, или наоборот. Фактически, некоторые браузеры явно запрещают это, например Firefox 8 и выше.</p>
<p>{{ languages ( {"zh-tw": "zh_tw/WebSockets/Writing_WebSocket_client_applications"} ) }}</p>
|