Protocol
Notice Will be rewritten introducing a test suite for server implementation.
URI
The socket URI to open a connection looks like the following:
chat?when=open&id=ed84f5a4-0772-43c6-ba95-e293c287be7c&transport=sse&heartbeat=false&lastEventId=25&_=1333818006226
The above URI is generated by urlBuilder
option with the open
when in the browser side and the following parameters are included in the form of query string by default.
when
: The purpose of request. Alwaysopen
when establishing a connection.id
: A unique socket identifier across the browser and the server.heartbeat
: A heartbeat interval. The value which is in a number format means that the browser will manage the connection using a heartbeat timer, and the value offalse
indicates no heartbeat.transport
: A required transport for the connection. It can have the following values unless you add or remove transport:ws
,sse
,streamxdr
,streamiframe
,streamxhr
,longpollajax
,longpollxdr
andlongpolljsonp
.lastEventId
: An id of the last event the browser received via the previous connection. If it does not exist, the value will be0
instead. If the server sends events in no order or asynchronously, this value could not be criterion for lost events._
: A value to prevent the browser from caching a GET request.
Opening connection
Prepare event-driven server.
WebSocket
There is nothing you have to do.
Streaming
The HTTP method GET is used to establish a connection, and applied transports are sse
, streamxdr
, streamiframe
and streamxhr
. For the server, the Server-Sent Events is a kind of the streaming.
- The response should be encoded in
utf-8
format. -sse
. Access-Control-Allow-Origin
header should be either*
or the value of theOrigin
request header. -streamxdr
.- The content-type header should be set to
text/event-stream
if the transport issse
and should be set totext/plain
if not forstreamiframe
to prevent iframe tag from parsing response as HTML. - The padding is required, which makes the transport object in the browser side aware of change of the response. The padding should be greater than one kilobyte (4K for Android browser 2 and 3), be composed of white space characters and end with
\r
,\n
or\r\n
. The socket in the browser side fires theopen
event when noticing padding. -streamxdr
,streamiframe
,streamxhr
in WebKit and Android browser 2 and 3 andsse
in Webkit and Firefox.
Long polling
The HTTP method GET is used to establish a connection, and applied transports are longpollajax
, longpollxdr
and longpolljsonp
. If the server is going to send data continuously, an additional measure is needed for the browser so as not to lose data.
Access-Control-Allow-Origin
header should be either*
or the value of theOrigin
request header. -longpollxdr
.- The content-type header should be set to
text/javascript
if the transport islongpolljsonp
, and for the others,text/plain
is fine. - If the
when
parameter isopen
, the server should complete the request immediately. The purpose of this is to tell the browser that the server is alive. The socket in the browser side fires theopen
event when the first request completes normally. After the completion, poll request has the when parameter whose value ispoll
notopen
. - If the
when
parameter ispoll
and the server did nothing to the request, completion of this request should be regarded as the end of a connection. So, the socket in the browser side fires theclose
event if the response is empty and poll if not.
Sending event
A final string to be sent to the browser is a JSON string representing an event object, and the inbound
handler in the browser side makes such a raw string into an event object. The event object should contain at least the type
property.
{"type":"message","data":"data","id":1,"reply":false}
type
: An event type.id
: An event id.data
: Data.reply
: Whether to request a reply.
WebSocket
A WebSocket message corresponds to a Portal event. Just send it.
Streaming
The response text should be formatted in the event stream format. This is a requirement of the sse
transport, but the rest of the streaming transports also accept that format for convenience. Break data up by \r
, \n
, or \r\n
, append data:
to the beginning of each line and \n
to the end of each line and print them. Finally, print \n
to mark the end of a single data. Android browser 2 and 3 need 4K padding at the top of each event.
Long polling
For the longpollajax
and longpollxdr
transport, the response text corresponds to a event. In case of the longpolljsonp
transport, the response text is a JavaScript code snippet executing a given callback in the browser side with data. The callback function name is passed as the request parameter callback
and the data should be escaped to a JavaScript string literal. All the long polling transports has to finish the request after processing.
Receiving event
A JSON string representing an event object is generated by outbound
handler in the browser side and sent to the server.
{"id":1,"socket":"341043d0-5564-4cdd-bb25-64dbe40b7a71","type":"message","data":"data","reply":false}
id
: An event id.socket
: A socket id.type
: An event type.data
: Data.reply
: Whether to request a reply.
WebSocket
A WebSocket message corresponds to a Portal event. Just receive it.
HTTP transport
For transports based on http protocol like streaming and long polling, the HTTP method POST is used to receive event. The POST request message body is like the following.
data={"id":1,"socket":"0c9d84f2-b8e3-4d65-bf41-7bb32f597b74","type":"message","data":"data","reply":false}
- The character encoding should be set to
UTF-8
explicitly. - The server has to access and parse the request’s message body directly, because to generalize how to extract data, the socket sets content type to
text/plain
notapplication/x-www-form-urlencoded
. Nevertheless, XDomainRequest doesn’t set content type header explicitly in a cross-origin connection. The problem results from the fourth restriction of the XDomainRequest. - The real data which the browser sends is a substring of the body which begins after the
data=
and extends to the end of the body. For your information, XDomainRequest doesn’t send body after unloading event.
Advanced
The following topics are not essential for two-way communication, but provide additional useful functions which makes the application more solid.
Retrieving lost event
If the transport is long polling and the server sends event during the idle time where the browser can’t receive events, those events could be vaporized. To help make up for lost event, every poll request has the lastEventIds
parameter which is a string concatenated by comma and contains event ids the socket in the browser side has received in the previous request’s response.
- If the transport is long polling, store an event to the cache when sending it.
- When the next poll request comes, remove events from the cache whose id is included in
lastEventIds
parameter. - If the cache is not empty, make it JSON array and send it.
Heartbeat
The heartbeat communication can resolve a state inconsistency problem which is a case that either of the server or the browser can’t recognize disconnection. The heartbeat
event is used. If the request parameter heartbeat
is in number format, the socket in the browser side continuously sends this event each specified time so the server should proceed according to the following instructions:
- Assign an integer greater than 5000 to the
heartbeat
option in the browser side. - Set a heartbeat timer in the server side that closes the connection after the heartbeat interval if the value is number.
- When the browser sends a heartbeat event, reset the timer and send back the event. If the server can’t respond in
5000
ms, the socket in the browser side will regard that the server dies and fire theclose
event.
Detecting disconnection
Although the heartbeat ensures the state synchronization regardless of the transport and the server, it takes a few seconds. Essentialy, this problem arises only with disconnection of transports based on http protocol, and instant detection can be possible by enabling the notifyAbort
option and processing abort request.
- Set the
notifyAbort
option to true. - If a request parameter
when
isabort
, close the corresponding socket.
Reply
The reply
event is a special event which is used to deliver the counterpart’s reply. When the server deals with browser-sent event if the value of the reply
property of event object is true
, a reply
event should be sent. The reply
event’s data must contain the id
property which is the event id the browser sent and can contain the data
and exception
properties. Then, done callback if exception
is false
or fail callback if it’s true
in the browser-side will be executed with the attached data.
Setting reply
The server, in common with the socket object in the browser-side, can set a reply callback to the socket object.
- Increment an event id, every time the server sends an event.
- Set a
reply
property of an event object totrue
if the callback is provided. - Client sent
reply
event is the same with what the server creates. Execute the corresponding callback with proper value on thereply
event.