hi,
when use websocket in uwsgi, if client close websocket connection, I will get en exception like " "unable to receive websocket message", so
i catch it as below:
try:
message = uwsgi.websocket_recv()
except IOError:
### how to do?
a compliant method to return [' '], but uwsgi will raise a exception "headers already sent",
so what should i do?
thanks
If your client brutally close the connection it is the right thing to do to generate an IOError (it is what happens at lower level). Are you sure you are not calling start_response() again ?
Maybe I find the problem.
If i write the code as below, uwsgi will have a error log like "headers already sent"
def application(env, start_response):
uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
while True:
try:
msg = uwsgi.websocket_recv()
except IOError:
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['']
uwsgi.websocket_send(msg)
and if I do not call start_response, everything is good. so the question is, uwsgi websocket api do the same thing like start_response function, when the req->headers_sent flag become true before I
call the start_response function?
and, if I use flask or webapp2 together with uwsgi , I write logic and return response in handler, but in framework, start_response will be called forcibly, so in this condition, how to catch client close websocket connection and gracefully exit the handler of framework without any error like "headers already sent" ?
thanks
uwsgi.websocket_handshake() internally does the same thing of start_response() (effectively the websocket handshake is a header exchange). If you cannot stop your app for calling it again you can wrap the flask callable (as an example) to map start_response as a noop for a specific url:
def application(environ, start_response):
if environ['PATH_INFO'] == '/websocket':
return app(environ, fake_start_response):
return app(app, start_response)
the idea of fake_start_response is wonderful, thanks very much
See the code example here:
http://uwsgi-docs.readthedocs.io/en/latest/articles/OffloadingWebsocketsAndSSE.html#common-pitfalls
However, I think a better approach is to check whether the request is a WebSocket handshake:
def application(environ, start_response):
if (environ.get('HTTP_CONNECTION', '').lower() == 'upgrade' and
environ.get('HTTP_UPGRADE', '').lower() == 'websocket'):
# The connection is upgrading to websocket. Use fake_start_response for it
start_response = fake_start_response
return sio_application(environ, start_response)
def fake_start_response(status, headers, exc_info=None):
pass
Sorry to intrude but what if someone is using uwsgi in django?
Most helpful comment
uwsgi.websocket_handshake() internally does the same thing of start_response() (effectively the websocket handshake is a header exchange). If you cannot stop your app for calling it again you can wrap the flask callable (as an example) to map start_response as a noop for a specific url: