基于flask和令牌桶算法的api限流接口

# 分词api接口:支持并发请求,检测用户5s内无请求则写回数据库
# ip限流一天20000次,一小时20000次,用户限流202500次左右
# 用户信息数据库ccpspider ccp_test_api
# post请求接收参数: data = {'username':用户名,'type':请求类型,'content':正文}
# 正文不超过1w# 响应结果: result = {'result':结果,'state':状态,'type':响应类型}
# user_dict = {用户名:[可使用次数,访问时间,令牌数]}

# coding=utf-8
# ******************************************************
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

# ******************************************************
import pyodbc



# ******************************************************
import time
import multiprocessing

# ******************************************************
from flask import Flask, render_template, request, jsonify
import jieba

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["20000 per day", "20000 per hour"]
)


def load_sql():
    conn = pyodbc.connect('DRIVER={SQL Server};SERVER=%s;DATABASE=%s;UID=%s;PWD=%s' % (
        MSSQL_HOST, MSSQL_DB_CCPSPIDER, MSSQL_USER, MSSQL_PWD))
    cur = conn.cursor()

    sql = """SELECT username,num
              FROM ccp_test_api"""
    cur.execute(sql)
    data = cur.fetchall()
    cur.close()
    conn.close()

    global user_dict
    for d in data:
        user_dict[d[0]] = [d[1], False, 2000]


user_dict = {}


@app.route("/", methods=['POST', ])
def fenci():
    if request.method == 'POST':
        global user_dict
        username = request.form.get('username')
        if username not in user_dict:  # dict查无则看sql是否存在此用户
            return jsonify({'state': '失败', 'type': '分词', 'result': '用户名错误!'})
        else:
            user_dict[username][1] = time.time()
        type = request.form.get('type')
        if type == '分词':
            content = request.form.get('content').replace(' ', '')
            if len(content) <= 10000:
                if user_dict[username][0] <= 0:
                    return jsonify({'state': '失败', 'type': '分词', 'result': '用户次数已用完!'})
                else:
                    if user_dict[username][2] > 0:
                        user_dict[username][0] -= 1
                        user_dict[username][2] -= 1
                        content_list = jieba.lcut(content)
                        # content_list = content
                        content_a = '/'.join(content_list)
                        return jsonify({'state': '成功', 'type': '分词', 'result': content_a})
                    else:
                        return jsonify({'state': '失败', 'type': '分词', 'result': '访问频率过快!!!'})
            else:
                return jsonify({'state': '失败', 'type': '分词', 'result': '文本过长!'})
        else:
            return jsonify({'state': '失败', 'type': '查无此项'})


def deal():
    app.run(host='0.0.0.0', port=6000, threaded=True)


# ********************************
import threading
import time


def update_sql(username, num):
    conn = pyodbc.connect('DRIVER={SQL Server};SERVER=%s;DATABASE=%s;UID=%s;PWD=%s' % (
        MSSQL_HOST, MSSQL_DB_CCPSPIDER, MSSQL_USER, MSSQL_PWD))
    cur = conn.cursor()

    sql = """update ccp_test_api
            set num=%d
            where username='%s'""" % (num, username)
    cur.execute(sql)
    cur.commit()

    global user_dict


num = 0


def deal_time():
    global timer
    timer = threading.Timer(5.0, deal_time)
    timer.start()  # 启用定时器
    global user_dict
    global num
    conn = pyodbc.connect('DRIVER={SQL Server};SERVER=%s;DATABASE=%s;UID=%s;PWD=%s' % (
        MSSQL_HOST, MSSQL_DB_CCPSPIDER, MSSQL_USER, MSSQL_PWD))
    cur = conn.cursor()
    for i in list(user_dict.keys()):
        if user_dict[i][1] != False:
            if (time.time() - user_dict[i][1]) > 5.0:
                try:
                    sql = """update ccp_test_api
                          set num=%d
                          where username='%s'""" % (user_dict[i][0], i)
                    cur.execute(sql)
                    cur.commit()
                except:
                    sql = """insert into ccp_test_api
                            (username,num)
                            value('%s',%d)""" % (i,user_dict[i][0])
                    cur.execute(sql)
                    cur.commit()
        if num == 4:
            if user_dict[i][2] <= 2000:
                user_dict[i][2] += 500
    if num >= 4:
        num = 0
    else:
        num += 1

    cur.close()
    conn.close()

# *******************************

if __name__ == '__main__':
    load_sql()
    jieba.lcut('dsdsfds')
    p = threading.Thread(target=deal)
    p.start()
    timer1 = threading.Timer(5.0, deal_time)
    timer1.start()


你可能感兴趣的:(基于flask和令牌桶算法的api限流接口)