Inside Flask - json 处理

Inside Flask - json 处理

在处理 web api 时,json 是非常好用的数据交换格式,它结构简单,基本上各种主流的编程语言都有良好的支持工具。

flask 中处理 json 时,对 json 加了一层包装,从而返回一个 Response 对象。简单的例子如下 ::

from flask import jsonify

...

@app.route('/hello')
def hello():
    result = {
        'status': 'success',
        'data': 'Hello, world!',
    }
    return jsonify(result)

flask 的 json 实现使用了 itsdangerous 中的 json 对象(来自 simplejson 或内置的 json),都在 flask/json.py 文件中。它在 json 的基础上加一些小的修改。对于 encoder ,增加了对 date ,UUID 和 内置 __html__ 属性(如 flask.Markup)等的处理 ::

class JSONEncoder(_json.JSONEncoder):
    ...
    def default(self, o):
        ...
        if isinstance(o, date):
            return http_date(o.timetuple())
        if isinstance(o, uuid.UUID):
            return str(o)
        if hasattr(o, '__html__'):
            return text_type(o.__html__())
        return _json.JSONEncoder.default(self, o) 

decoder 继承 _json.JSONDecoder ,没有修改。

除了基本的 dump / dumps / load / loads , flask 在这里还做了对 unicode 的处理和对 html 的转换处理。它提供了两个方法来处理 unicode 字符串 ::

def _wrap_reader_for_text(fp, encoding):
    if isinstance(fp.read(0), bytes):
        fp = io.TextIOWrapper(io.BufferedReader(fp), encoding)
    return fp
...
def _wrap_writer_for_text(fp, encoding):
    try:
        fp.write('')
    except TypeError:
        fp = io.TextIOWrapper(fp, encoding)
    return fp

对于在字节流, flask 在这里对它进行了包装,成为 unicode 文本流,再交给 json 处理。

对于 html ,由于html 中带有特殊的字符,需要转换 ::

def htmlsafe_dumps(obj, **kwargs):
    rv = dumps(obj, **kwargs) \
        .replace(u'<', u'\\u003c') \
        .replace(u'>', u'\\u003e') \
        .replace(u'&', u'\\u0026') \
        .replace(u"'", u'\\u0027')
    if not _slash_escape:
        rv = rv.replace('\\/', '/')
    return rv

最后,就是我们在处理 json 常用的 jsonify 函数 ::

def jsonify(*args, **kwargs):
	indent = None
    separators = (',', ':')

    if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] and not request.is_xhr:
        indent = 2
        separators = (', ', ': ')

    if args and kwargs:
        raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
    elif len(args) == 1:  # single args are passed directly to dumps()
        data = args[0]
    else:
        data = args or kwargs

    return current_app.response_class(
        (dumps(data, indent=indent, separators=separators), '\n'),
        mimetype=current_app.config['JSONIFY_MIMETYPE']
    )

jsonify 函数在 dumps 的结果基础上,用 response_class 对结果进行了包装,并且给返回的数据头部的 mimetype 加上 json 类型(默认为 application/json ,可修改 JSONIFY_MIMETYPE 配置)

在使用 jsonify 函数时,需要注意只能使用 args 或 kwargs 其中一种方式,而 args 长度为1 时返回的是 args[0] 。其它模块也使用到 json 相关的功能,如 request 中从请求加载 json 数据等,用到 load 数据的功能。

posted @ 2016-09-14 00:31  drop *  阅读(3160)  评论(0编辑  收藏  举报