Flask中设置JSON到cookie,并在客户端(JavaScript)解码

3 投票
3 回答
4570 浏览
提问于 2025-04-17 21:21

我在Flask中设置一个cookie,代码如下:

response.set_cookie('notice', value = json.dumps(someObject), max_age=None)

如果我在服务器上打印json.dumps(someObject),我得到:

{"message": "hello", "type": "success"}

在客户端,它变成了:

"{\"message\": \"hello\"\054 \"type\": \"success\"}"

我想在JavaScript客户端解码它,这到底是什么格式呢?

我想解码它并传递给angular.fromJson(),看起来至少需要处理一下(把\"去掉),但我很惊讶看到\054(这是逗号的八进制ASCII码)

3 个回答

0

Flask(Python)和JavaScript之间的双向JSON Cookie

在Python中,读取时需要用urllib来解码

if "sensorcookie" in request.cookies:
    ck = json.loads(urllib.parse.unquote(request.cookies.get("sensorcookie")))
else:
    ck = {}
tz = "undefined" if os.environ.get("TZ") is None else os.environ.get("TZ")
ck = {"HOST_ENV":os.environ["HOST_ENV"], "TZ": tz, **ck}
resp.set_cookie("sensorcookie", json.dumps(ck))

在JavaScript中,使用js-cookies。需要在进行JSON解析之前,替换掉转义的逗号和三个反斜杠。我已经构建了一个“模块”来完成这个工作

// https://yuiblog.com/blog/2007/06/12/module-pattern/
var sensorcookies = function () {
    const defaultopts = {righttoleft:true, graphtype:"line", freq:"", pointsslider:100, pointstoplot:20, tickinterval:1, TZ:""};
    const name = "sensorcookie";
    function convertraw() {
        var t = Cookies.get(name);
        return (!t) ? defaultopts : { ...defaultopts, ...JSON.parse(t.replace(/\\054/g, ",").replace(/\\/g, ""))};
    }
    function privateget(attr) {
        var opts = convertraw();
        return opts[attr];
    }
    function privateset(attr, value) {
        var opts = convertraw();
        opts[attr] = value;
        Cookies.set(name, JSON.stringify(opts));
    }
    // waitforcookies();
    return {
        version: "1.0",
        get: (attr) => { return privateget(attr);},
        set: (attr, value) => { privateset(attr, value);},
        log: () => { Cookies.set(name, convertraw()); console.log(JSON.stringify(convertraw()));}, 
        val: () => { return convertraw(); }
    };
}();  // NB parens so makes it feel like a "module"
0

今天我也遇到了同样的问题,但情况似乎有所变化。

首先,把cookie发送回去其实很简单:

cookie_str = json.dumps(mydictionary, separators=(',', ':'))
resp.set_cookie('cookiename', cookie_str, None, None, '/') 

在浏览器的JavaScript中,我使用js-cookies这个项目来读取cookie,方法如下:

var cookie2 = Cookies.noConflict();
var cookiejs = cookie2.getJSON('cookiename');
var one = ca.field1;
var two = ca.field2;

看起来在我的情况下,大括号没有被正确处理。因此,我需要把大括号替换成转义后的版本,也就是\{\}。不过,替换之后,我不能用getJSON,而是得用jquery的$.parseJSON()函数,这样才能得到一个可用的json对象。

我还是没弄明白怎么才能让cookie的json字符串正常工作,而不需要在JavaScript那边重新转义大括号。使用转义和jquery的方法有点小技巧……但确实有效。

另外,我在AWS Lambda上使用Zappa-Flask,不确定这是否影响了我的cookie。

6

为了确保在Cookie头中安全使用,Werkzeug库会对cookie的值进行引号处理。这意味着它会把任何逗号、分号、双引号和反斜杠都加上引号:

cookie_quoting_map = {
    b',' : b'\\054',
    b';' : b'\\073',
    b'"' : b'\\"',
    b'\\' : b'\\\\',
}

除此之外,除了字母、数字和这些字符!#%&'~_`><@,:/$*+-.^|)(?}{=以外的任何东西都会被编码成八进制代码。如果cookie中有任何被转义的值,整个cookie也会被双引号包围。

如果你想在JavaScript中访问cookie的值,你需要再解码一次。以斜杠开头的三位数字是八进制值;可以使用String.replace()来处理:

function decode_flask_cookie(val) {
    if (val.indexOf('\\') === -1) {
        return val;  // not encoded
    }
    val = val.slice(1, -1).replace(/\\"/g, '"');
    val = val.replace(/\\(\d{3})/g, function(match, octal) { 
        return String.fromCharCode(parseInt(octal, 8));
    });
    return val.replace(/\\\\/g, '\\');
}

示例:

> // recreate properly escaped value
> var cookie = "\"{\\\"message\\\": \\\"hello\\\"\\054 \\\"type\\\": \\\"success\\\"}\""
> cookie
""{\"message\": \"hello\"\054 \"type\": \"success\"}""
> decode_flask_cookie(cookie)
"{"message": "hello", "type": "success"}"
> JSON.parse(decode_flask_cookie(cookie))
Object {message: "hello", type: "success"}

撰写回答