Why must a Flask session's value be JSON seria

2020-07-08 07:51发布

问题:

I'm trying to instantiate a basic Model instance for the user session in my Flask application. I'm caught off guard by the requirement that my class be JSON serializable. I thought the session dictionary was just an arbitrary construct to store session information but it sounds like there's more constraints surrounding its usage, one of which is apparently the values be JSON serializable. What other constraints are there and what is the purpose of this JSON constraint exactly? Is it a hard expectation for web apps to persist their user sessions via JSON? Where does this requirement come from/is inspired by?

@app.route( '/' , methods=['GET', 'POST'] )
def index():
    """index  takes user to the home page of the application.
    """

    # Create model instance for this user session
    if 'model' not in session :
        session['model'] = Model( )


File "C:\Anaconda3\lib\site-packages\flask\json.py", line 83, in default
return _json.JSONEncoder.default(self, o)
File "C:\Anaconda3\lib\json\encoder.py", line 173, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Model.Model object at 0x000000000770B6D8> is not JSON serializable

Just for additional background it looks like the session object is a LocalProxy instance which may clue into the design of things.

>>> type( session )
<class 'werkzeug.local.LocalProxy'>

回答1:

Ok, so there's some good commentary on this in Miguel Grinberg's Flask Workshop at Pycon 2015. The need for JSON support has to do with where this session data is persisted, which is as a cookie on the client. Therefore the data has to serialize to bridge the gap between server and client. According to him...

So flask supports this session object,... inside any route function while your handling a request you refer to session as a dictionary. And anything you write is remembered, next time you can look for it and it will be there and it will be user specific.

If you're interested to know how that works, this is Flask internals, anything you write to this dictionary, Flask will put in a cookie and it will send it to the Client. So this will be stored in the client's web browser. It will be a cookie that is crytographically signed, to make sure that the user does not tamper with it, that there are no attacks possible. You can see what's in the cookie but you cannot modify it. By default Flask writes the data itself in the cookie and that cookie goes to the client. What many other frameworks do by default is different. Basically what they do is they write the data in a file or database in the server, and then they write a cookie with an id that identifies that data, and then they send the id in the cookie. So Flask by default sends the whole data in the cookie so there's no need to store anything in the server.

So in my particular case to get around this I had to implement a JSONEncoder and first encode it before transferring it to my session

<<Model.py>>
class ModelEncoder( JSONEncoder ) :
    def default( self , obj ) :
        if isinstance( obj , Model ):
            return obj.to_json()
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default( self , obj )

class Model( JSONEncoder ) :
    ....
    def to_json( self ) :
        """
        to_json transforms the Model instance into a JSON string
        """
        return jsonpickle.encode( self )


<<FlaskApp.py>>
    ...
    # Create model instance for this user session
    if 'model' not in session :
        session['model'] = ModelEncoder().encode( Model( ) )


标签: flask