Flask请求参数类型判断

一个最小的Flask应用

# encoding:utf-8
# app.py
from flask import Flask, jsonify, request
__author__ = '零四二零'

app = Flask(__name__)

@app.route('/', methods=['GET'])
def fight():
    name = request.args.get('name')
    return jsonify(dict(data=name))
# encoding:utf-8
# runserver.py
from app import app
__author__ = '零四二零'

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, threaded=True)

请求http://0.0.0.0:5000?name=123

image.png

一个简单的想法是在函数内部判断name的属性,不符合就返回错误信息,实现起来很简单

# encoding:utf-8
# app.py
from flask import Flask, jsonify, request
__author__ = '零四二零'

app = Flask(__name__)

@app.route('/', methods=['GET'])
def fight():
    name = request.args.get('name', '')
    if not name:
        return jsonify(dict(error='缺少参数'))
    try:
        name = int(name)
    except ValueError:
        return jsonify(dict(error='参数格式错误'))
    return jsonify(dict(data=name))

请求http://0.0.0.0:5000

image.png

请求http://0.0.0.0:5000?name=fight

image.png

这种写法非常不美,把类型判断剥离开来,改成装饰器,统一调用

# encoding:utf-8
# validator.py
from flask import request, jsonify
__author__ = '零四二零'

def validator_int(func):
    def _decorate():
        name = request.args.get('name', '')
        if not name:
            return jsonify(dict(error='缺少参数'))
        try:
            name = int(name)
        except ValueError:
            return jsonify(dict(error='参数格式错误'))
        return func()
    return _decorate
# encoding:utf-8
# app.py
from flask import Flask, jsonify, request
from validator import validator_int
__author__ = '零四二零'

app = Flask(__name__)

@app.route('/', methods=['GET'])
@validator_int
def fight():
    name = request.args.get('name', '')
    return jsonify(dict(data=name))

大功告成,继续优化,使用Flask的异常处理,并支持默认参数

# encoding:utf-8
# validator.py
from flask import request
__author__ = '零四二零'

def validator_int(func):
    def _decorate():
        arg = request.args.get('name', '666')
        if not arg:
            raise Exception('缺少参数')
        try:
            name = int(arg)
        except ValueError:
            raise Exception('参数格式错误')
        return func(arg)
    return _decorate
# encoding:utf-8
# app.py
from flask import Flask, jsonify
from validator import validator_int
__author__ = '零四二零'

app = Flask(__name__)

@app.errorhandler(Exception)
def error(e):
    return jsonify(dict(error=e.message))

@app.route('/', methods=['GET'])
@validator_int
def fight(name):
    return jsonify(dict(data=name))

请求http://0.0.0.0:5000

image.png

默认是写在 validator_int里并不是最好的选择,移到 fight中,需要用到 inspect库来获取 fight的参数信息

# encoding:utf-8
# app.py
from flask import Flask, jsonify
from validator import validator_int
__author__ = '零四二零'

app = Flask(__name__)

@app.errorhandler(Exception)
def error(e):
    return jsonify(dict(error=e.message))


@app.route('/', methods=['GET'])
@validator_int
def fight(name='666'):
    return jsonify(dict(data=name))
# encoding:utf-8
# validator.py
import inspect
from flask import request
__author__ = '零四二零'

def validator_int(func):
    def _decorate():
        arg = request.args.get('name', '')
        if not arg:
            func_args = inspect.getargspec(func)
            defaults = func_args.defaults[0]
            arg = func_args.args[0]
        try:
            name = int(defaults)
        except ValueError:
            raise Exception('参数格式错误')
        return func(**{arg: defaults})
    return _decorate

支持多参数操作,有默认值的加上默认值

# encoding:utf-8
# validator.py
import inspect
import json
from flask import request
__author__ = '零四二零'

REQUEST_METHOD_MAP = {'GET': 'args', 'POST': 'form'}


def _params_covert(val):
    val = val[0] if isinstance(val, list) else val
    try:
        val = json.loads(val)
    except (ValueError, TypeError):
        pass
    return val


def _get_request_params():
    params = request.json or {}
    for k, v in dict(getattr(request, REQUEST_METHOD_MAP.get(request.method))).iteritems():
        params[k] = _params_covert(v)
    return params


def _param_int_validator(val):
    try:
        _ = int(val)
    except (ValueError, TypeError):
        return False
    return True

def validator_int(func):
    def _decorate():
        params = _get_request_params()
        func_args = inspect.getargspec(func)
        default_val, args, kwargs, args_len = func_args.defaults or [], [], {}, len(func_args.args)
        for index, func_arg in enumerate(func_args.args):
            default_index = index + len(default_val) - args_len
            if default_index < 0:
                if func_arg not in params:
                    raise Exception('缺少参数:{0}'.format(func_arg))
                else:
                    if not _param_int_validator(params[func_arg]):
                        raise Exception('参数格式错误')
                    args.append(params[func_arg])
            else:
                kwargs[func_arg] = params[func_arg] if func_arg in params else default_val[default_index]
        for k, v in kwargs.iteritems():
            if not _param_int_validator(v):
                raise Exception('参数:{0} 格式错误'.format(k))
        return func(*args, **kwargs)
    return _decorate
# encoding:utf-8
# app.py
from flask import Flask, jsonify
from validator import validator_int
__author__ = '零四二零'

app = Flask(__name__)

@app.errorhandler(Exception)
def error(e):
    return jsonify(dict(error=e.message))

@app.route('/', methods=['GET'])
@validator_int
def fight(sex, name='666', age='18'):
    return jsonify(dict(name=name, age=age, sex=sex))

请求http://0.0.0.0:5000?sex=1

image.png

再接再厉,支持指定参数类型判断,validator_int需要接受一个dict参数,里面是各个参数的字段类型

# encoding:utf-8
# validator.py
import inspect
import json
from flask import request
__author__ = '零四二零'

REQUEST_METHOD_MAP = {'GET': 'args', 'POST': 'form'}


def _params_covert(val):
    val = val[0] if isinstance(val, list) else val
    try:
        val = json.loads(val)
    except (ValueError, TypeError):
        pass
    return val


def int_field(value):
    try:
        _ = int(value)
    except (ValueError, TypeError):
        return False
    return True


def str_field(value):
    try:
        import re
        if not re.compile('.*').match(value):
            return False
    except (ValueError, TypeError):
        return False
    return True


def list_field(value):
    try:
        if not isinstance(value, list):
            value = json.loads(value)
            _ = [x.strip() for x in value.split(',')]
    except (ValueError, TypeError):
        return False
    return True


def dict_field(value):
    try:
        if not isinstance(value, dict):
            _ = json.loads(value)
    except (ValueError, TypeError):
        return False
    return True


def bool_field(value):
    try:
        bool(value)
    except (ValueError, TypeError):
        return False
    return True


def float_field(value):
    try:
        _ = float(value)
    except (ValueError, TypeError):
        return False
    return True


def _get_request_params():
    params = request.json or {}
    for k, v in dict(getattr(request, REQUEST_METHOD_MAP.get(request.method))).iteritems():
        params[k] = _params_covert(v)
    return params


def validator_int(param_fields):
    def _decorate(func):
        def __decorate():
            params = _get_request_params()
            func_args = inspect.getargspec(func)
            default_val, args, kwargs, args_len = func_args.defaults or [], [], {}, len(func_args.args)
            for index, func_arg in enumerate(func_args.args):
                if func_arg not in param_fields:
                    raise Exception('参数:{0}, 未指明类型'.format(func_arg))
                default_index = index + len(default_val) - args_len
                param_func = param_fields[func_arg]
                if default_index < 0:
                    if func_arg not in params:
                        raise Exception('缺少参数:{0}'.format(func_arg))
                    else:
                        if not param_func(params[func_arg]):
                            raise Exception('参数:{0}格式错误, 需要类型:{1}'.format(func_arg, param_func.__name__))
                        args.append(params[func_arg])
                else:
                    kwargs[func_arg] = params[func_arg] if func_arg in params else default_val[default_index]
            for k, v in kwargs.iteritems():
                if not param_fields[k](v):
                    raise Exception('参数:{0} 格式错误, 需要类型:{1}'.format(k, param_fields[k].__name__))
            return func(*args, **kwargs)
        return __decorate
    return _decorate
# encoding:utf-8
# app.py
from flask import Flask, jsonify
from validator import validator_int, int_field, dict_field, list_field
__author__ = '零四二零'

app = Flask(__name__)


@app.errorhandler(Exception)
def error(e):
    return jsonify(dict(error=e.message))


@app.route('/', methods=['GET'])
@validator_int(dict(name=dict_field, sex=list_field, age=int_field))
def fight(sex, name, age=18):
    return jsonify(dict(name=name, age=age, sex=sex))

请求http://0.0.0.0:5000?sex=[1,2,3]&name={"name":"fight"}

Flask请求参数类型判断_第1张图片
image.png

请求 http://0.0.0.0:5000?sex=[1,2,3]&name=123

image.png

「欢迎分享,优化」

你可能感兴趣的:(Flask请求参数类型判断)