Flask-socketio: React Native: Received data was not a string or was not recognized encoding

Created on 24 Aug 2018  Â·  7Comments  Â·  Source: miguelgrinberg/Flask-SocketIO

I am trying to create a connection between react native and a flask-socketio application.

I noticed that a normal browser could connect to the backend while react-native could not. Upon further investigation, calls from normal browsers included a sid value in the query, while calls from react-native do not.

It looks like the sid is initially set by a GET request to flask-socketio. When I tried curling that request I got this response.

�0{"sid":"a4ff1b37b91243c7a89a66f7159902f4","upgrades":[],"pingTimeout":60000,"pingInterval":25000}�40

Note the weird characters at the beginning and end. Also, in react native I get a somewhat cryptic error that reads: 'Received data was not a string or was not recognized encoding'.

It SEEMS like normal browsers are enable to interpret this encoding but react native is not. I'd like to get flask-socketio to send paramaters encoded in a more standard way if possible, which will hopefully address the issue in react native. I've tried changing the 'json' parser passed to Flask-socketio and this doesn't seem to help. Here's my code:

Server

import json
from flask_socketio import SocketIO
from config import config

CONFIG_NAME = os.getenv('TS_CONFIG_ENV', 'dev')

APP: Flask = Flask(__name__)
APP.config.from_object(config.CONFIG[CONFIG_NAME])
socketio = SocketIO(APP, async_mode='gevent', json=json)
socketio.run(APP, host=APP.config['HOST'], port=APP.config['PORT'], log_output=True)

I've tried using both polling and websockets on the client, neither seems to work.

question

Most helpful comment

Thanks so much! Adding query: 'b64=1' resolved the issue in react-native. It's using polling rather than websockets, but I can debug the websockets side of things later.

If I had to guess, I'd say that the XMLHttpRequest handler in react native doesn't know how to deal with binary encoding. I didn't include b64=1 in my request to node, it just defaulted to that, so maybe they're the ones not following the standard?

Thanks again!

All 7 comments

The "weird" characters are the binary encoding of Socket.IO packets. This is a standard format documented in the Socket.IO protocol.

The sid is the Socket.IO session id. It is returned by the server in the response to the initial connection request, along with other settings. The client is supposed to send that sid in the query string of all subsequent requests.

See https://github.com/miguelgrinberg/Flask-SocketIO/issues/716 for a similar issue. In that case the problem was addressed by connecting via websocket without passing through long-polling first.

Connecting via websockets didn't work in this case. It looks like the binary encoding isn't being interpreted by react native. Is there a way to try a different encoding?

To be more specific:

Setting transports: ['websocket'] does not resolve the issue.

Update: when I try a node implementation of socket.io the encoding on this response is different:

node:

96:0{"sid":"ZddvxiNSLbHI1b8NAAAB","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":5000}2:40

flask-socketio:

�0{"sid":"f985afd2d41846a2bbe7b7955440e7b0","upgrades":[],"pingTimeout":60000,"pingInterval":25000}�40 

(Note, some special characters removed because they were breaking the github comment.)

React native can connect successfully to the node server, but not to the flask-socketio server.

Yes, this client appears to have trouble with the binary representation, but that is the default. If it wants the text representation it should ask for it by sending b64=1 in the query string, which apparently the second client that you tested uses. See https://github.com/socketio/engine.io-protocol#payload for the best reference regarding these formats.

I should note that none of this applies to WebSocket, and that is why going direct to WebSocket worked for this other person. Not sure why it does not work for you, but I'm certain you must have a different problem since the "payload" encoding is a concept that is only used in HTTP.

Thanks so much! Adding query: 'b64=1' resolved the issue in react-native. It's using polling rather than websockets, but I can debug the websockets side of things later.

If I had to guess, I'd say that the XMLHttpRequest handler in react native doesn't know how to deal with binary encoding. I didn't include b64=1 in my request to node, it just defaulted to that, so maybe they're the ones not following the standard?

Thanks again!

@davidgljay did you made it work? I set the b64 param for the GET request and it made the first request work, so I've got a socket.io session id, but GET request for protocol switch wasn't sent after that.

Yes, this client appears to have trouble with the binary representation, but that is the default. If it wants the text representation it should ask for it by sending b64=1 in the query string, which apparently the second client that you tested uses. See https://github.com/socketio/engine.io-protocol#payload for the best reference regarding these formats.

Maybe you should include this in the documentation ¯_(ツ)_/¯

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zuifengwuchou picture zuifengwuchou  Â·  5Comments

novice79 picture novice79  Â·  3Comments

chaitanyavolkaji picture chaitanyavolkaji  Â·  3Comments

huangganggui picture huangganggui  Â·  3Comments

thehelpfulbees picture thehelpfulbees  Â·  4Comments