El servidor de tornado arroja un error La secuencia está cerrada
Estoy tratando de implementar una página web de chat / echo muy básica.
Cuando el cliente visita / notifica: 8000 se carga un sitio simple, en el lado del cliente se inicia una solicitud para establecer una escucha, en el back-end, el recuento de la nube se actualiza y se envía a todos los clientes existentes.
Cada vez que el usuario ingresa algo en un cuadro de texto, se hace un POST al back-end y todos los demás clientes reciben una actualización con ese texto.
Aquí está la plantilla de front-end
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
</head>
<body>
<p>session: <span id="session">{{ session }}</span><br/>
client count: <span id="clientCount">{{ clientCount }}</span><br/>
<span id="welcome">...registering with notify...</span></p>
<div style="width: 600px; height: 100px; border: 1px solid black; overflow:auto; padding: 4px;" id="chatText">
</div>
<div>
<span>enter text below:</span><br />
<input type="text" id="textInput"></textarea>
<div>
<script>
$(document).ready(function() {
document.session = $('#session').html();
setTimeout(initializeListener, 100);
$('#textInput').keypress(function(e) {
// e.preventDefault();
if(e.keyCode == 13 && !e.shiftKey) {
var text = $('#textInput').val();
submitChatText(text);
return false;
}
});
});
var logon = '1';
function initializeListener() {
console.log('initializeListener() called');
jQuery.getJSON('//localhost/notify/listen', {logon: logon, session: document.session},
function(data, status, xhr) {
console.log('initializeListener() returned');
if ('clientCount' in data) {
$('#clientCount').html(data['clientCount']);
}
if ('chatText' in data) {
text = $('#chatText').html()
$('#chatText').html(data['chatText'] + "<br />\n" + text);
}
if (logon == '1') {
$('#welcome').html('registered listener with notify!');
logon = '0';
}
setTimeout(initializeListener, 0);
})
.error(function(XMLHttpRequest, textStatus, errorThrown) {
console.log('error: '+textStatus+' ('+errorThrown+')');
setTimeout(initializeListener, 100);
});
}
function submitChatText(text) {
console.log('submitChatText called with text: '+text)
jQuery.ajax({
url: '//localhost/notify/send',
type: 'POST',
data: {
session: document.session,
text: ''+text
},
dataType: 'json',
//beforeSend: function(xhr, settings) {
// $(event.target).attr('disabled', 'disabled');
//},
success: function(data, status, xhr) {
console.log('sent text message')
$("#textInput").val('');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
console.log('error: '+textStatus+' ('+errorThrown+')');
}
});
}
</script>
</body>
</html>
Aquí está el código del servidor:
import tornado.ioloop
import tornado.web
import tornado.options
from uuid import uuid4
import json
class Client(object):
callbacks = {}
chat_text = ''
def register(self, callback, session, logon=False):
self.callbacks[session] = callback
if logon == '1':
self.notifyCallbacks()
def notifyCallbacks(self):
result = {}
result['clientCount'] = self.getClientCount()
if self.chat_text:
result['chatText'] = self.chat_text
for session, callback in self.callbacks.iteritems():
callback(result)
self.callbacks = {}
def sendText(self, session, text):
self.chat_text = text
self.notifyCallbacks()
self.chat_text = ''
def getClientCount(self):
return len(self.callbacks)
class Application(tornado.web.Application):
def __init__(self):
self.client = Client()
handlers = [
(r"/notify", MainHandler),
(r"/notify/listen", ListenHandler),
(r"/notify/send", SendHandler)
]
settings = dict(
cookie_secret="43oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
template_path="templates/notify",
)
tornado.web.Application.__init__(self, handlers, **settings)
class ListenHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
logon = self.get_argument('logon')
session = self.get_argument('session')
self.application.client.register(self.on_message, session, logon)
def on_message(self, result):
json_result = json.dumps(result)
self.write(json_result)
self.finish()
class SendHandler(tornado.web.RequestHandler):
def post(self):
text = self.get_argument('text')
session = self.get_argument('session')
self.application.client.sendText(session, text)
class MainHandler(tornado.web.RequestHandler):
def get(self):
session = uuid4()
client_count= self.application.client.getClientCount()
self.render("testpage.html", session=session, clientCount=client_count)
if __name__ == '__main__':
application = Application()
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()
Luego, a veces, el servidor genera errores cuando cierro una pestaña e intento transmitir desde otra. El error es así:
ERROR:root:Uncaught exception POST /notify/send (127.0.0.1)
HTTPRequest(protocol='http', host='localhost', method='POST', uri='/notify/send', version='HTTP/1.1', remote_ip='127.0.0.1', body='session=e5608630-e2c7-4e1a-baa7-0d74bc0ec9fc&text=swff', headers={'Origin': 'http://localhost', 'Content-Length': '54', 'Accept-Language': 'en-US,en;q=0.8', 'Accept-Encoding': 'gzip,deflate,sdch', 'X-Forwarded-For': '127.0.0.1', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Host': 'localhost', 'X-Requested-With': 'XMLHttpRequest', 'X-Real-Ip': '127.0.0.1', 'Referer': 'http://localhost/notify', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'})
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/tornado/web.py", line 1021, in _execute
getattr(self, self.request.method.lower())(*args, **kwargs)
File "test.py", line 66, in post
self.application.client.sendText(session, text)
File "test.py", line 30, in sendText
self.notifyCallbacks()
File "test.py", line 24, in notifyCallbacks
callback(result)
File "test.py", line 60, in on_message
self.finish()
File "/usr/lib/python2.7/site-packages/tornado/web.py", line 701, in finish
self.request.finish()
File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 433, in finish
self.connection.finish()
File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 187, in finish
self._finish_request()
File "/usr/lib/python2.7/site-packages/tornado/httpserver.py", line 223, in _finish_request
self.stream.read_until(b("\r\n\r\n"), self._header_callback)
File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 153, in read_until
self._try_inline_read()
File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 381, in _try_inline_read
self._check_closed()
File "/usr/lib/python2.7/site-packages/tornado/iostream.py", line 564, in _check_closed
raise IOError("Stream is closed")
IOError: Stream is closed
Obviamente, esto se debe a que la pestaña estaba cerrada, por lo que el cliente ya no está escuchando, pero eso debería ser algo normal, ¿cómo puedo manejar esa situación con más gracia?
Lo único que pude encontrar sobre este error, fue otra publicación de stackoverflow, la sugerencia fue verificar si la conexión se completó antes de llamar al método finish ():
if not self._finished:
self.finish()
Sin embargo, cuando intenté eso, no parecía ayudar, seguía teniendo el mismo error, O obtendría otro errorAssertionError: Solicitud cerrada que no pude encontrar ninguna ayuda en