Разработка приложений на основе API на основе колбы (C)

Python
Разработка приложений на основе API на основе колбы (C)

обо мне
Небольшой программист в мире программирования, в настоящее время работает руководителем команды в предпринимательской команде.Стек технологий включает Android, Python, Java и Go, который также является основным стеком технологий нашей команды.
Гитхаб:github.com/hylinux1024
Публичный аккаунт WeChat: гневный код

Первые две главы описывают структуру программ иAPIСоглашение в основном составлено. В этой статье не предполагается реализовывать интерфейс каждого модуля в начале, потому что это в основном код бизнес-логики, и код размещается на протяжении всей статьи, что было бы катастрофой.

«Предыдущая глава»правильномодуль авторизации входаИнтерфейс реализован.При написании этого текста я также поставилПользовательский модульБыли реализованы список пользователей, запрос информации о пользователе, обновление информации о пользователе и другие интерфейсы. При написании этого я обнаружил, что в нем много повторяющейся логики. Например, логика проверки параметров входа, обработки информации об ошибках и т. д., по сути, эти логики могут обрабатываться единообразно.

0x00 унифицированная обработка ошибок

Если клиент обращается к следующемуНе определеноИнтерфейс

http://127.0.0.1:5000/api/auth/something

вернет следующую информацию

Not Found

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

или есть немногоошибка работы базы данных, что также приводит к внутренней ошибке сервера

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

эта информация об использовании этой системыAPIне очень дружелюбно относится к клиентуjsonданные возвращаются.

к этомуhttpЧтобы запросить унифицированную обработку сообщений об ошибках протокола или реализовать пользовательские страницы ошибок, вам необходимо использовать@errorhandlerэтот декоратор.

существуетapp.py, добавьте следующие два метода

@app.errorhandler(404)
def not_found_error(error):
    return make_response_error(404, error.description)


@app.errorhandler(500)
def internal_error(error):
    db.session.rollback()
    return make_response_error(500, error.description)

при запросе несуществующегоurl, наша система должна вернуть что-то вроде

{
"code": 404,
"msg": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
}

Это согласуется с нашим определенным протоколом интерфейса структуры данных.

0x01 Маркер пользователя для единой аутентификации

Так как в системе много интерфейсов, требующих авторизации пользователейtokenможно получить только доступ, поэтому каждый интерфейс входит в системуtokenпроверка.
Открытьusers.pyмодуль, следующие интерфейсы имеютtokenЛогика проверки

@bp.route('/show', endpoint='show')
def show_user_info():
    uid = request.args.get('userId')
    peer_id = request.args.get('peerId')
    token = request.args.get('token', '')
    if not UserInfo.check_token(uid, token):
        return make_response_error(504, 'no operation permission')

    ...
    # 省略不必要的代码
    return make_response_ok(data)
@bp.route('/hot/list', endpoint='list')
def list_hot_user():
    uid = request.args.get('userId')
    token = request.args.get('token', '')
    if not UserInfo.check_token(uid, token):
        return make_response_error(504, 'no operation permission')
    ...
    # 省略不必要的代码
    return make_response_ok(obj)

@bp.route('/update', methods=["POST"], endpoint="update")
def update_user():
    uid = request.form.get('userId', '')
    token = request.form.get('token', '')

    if not UserInfo.check_token(uid, token):
        return make_response_error(504, 'no operation permission')

    ...
    # 省略不必要的代码
    return make_response_ok(data={"data": user.id})

Все три интерфейса выше имеют одинаковую проверку.tokenлогика

if not UserInfo.check_token(uid, token):
        return make_response_error(504, 'no operation permission')

И интерфейс этой системы гораздо больше, чем они.Если каждый интерфейс пишет один и тот же логический код, это выглядит не очень элегантно.

Это невозможно с предыдущим определением@validsignПодобно декораторам, определите@require_tokenдекоратор?
Ответ положительный.

Но здесь я хочу изменить напрямую@validsignЭта функция декоратора, добавьте к ней параметр@validsign(require_token=True)Таким образом, он должен быть более кратким в использовании.

def validsign(require_token=False, require_sign=True):
    """
    验证签名,token信息
    :param require_token: 是否验证token
    :param require_sign: 是否验证签名
    :return:
    """
    def decorator(func):
        def wrapper():
            params = _get_request_params()
            if require_sign:
                appkey = params.get('appkey')
                sign = params.get('sign')
                csign = signature(params)
                if not appkey:
                    return make_response_error(300, 'appkey is none.')
                if csign != sign:
                    return make_response_error(500, 'signature is error.')
            if require_token:
                token = params.get('token')
                uid = params.get('userId')
                if not UserInfo.check_token(uid, token):
                    return make_response_error(504, 'no operation permission')
            return func()
        return wrapper
    return decorator

по параметруrequire_tokenа такжеrequire_signЛогикой проверки интерфейса управления можно гибко управлять, что также очень полезно для отладки в процессе разработки.

положи сюдаtokenЛогика проверки заключена вUserInfoВнутри это статический метод

@staticmethod
def check_token(uid, token):
    if not token or not uid:
        return False
    user = UserInfo.query.filter_by(id=uid).first()
    if not user:
        return False
    if not user.user_auth:
        return False
    return user.user_auth.token == token

Модульный тест 0x02

из-за предыдущего@validsignФункция декоратора была изменена. Модульный тест может убедиться, что наша модификация не повлияет на конкретную бизнес-логику, и может гарантировать, что модификация сделана на исходной основе. Это консервативный способ ведения дел.
Аналогично вновь добавленные модулиusers.pyТакже требуются соответствующие возможности модульного тестирования.

def test_hotlist(self):
    import math
    nonce = math.floor(random.uniform(100000, 1000000))
    params = {'phone': '18922986865', 'userId': '100784', 'appkey': '432ABZ',
              'token': '575f680ddbd0d494a1b5fad8497293d2',
              'timestamp': datetime.now().timestamp(),
              'nonce': nonce}
    sign = signature(params)
    params['sign'] = sign

    respdata = self.app.get("/api/user/hot/list", data=params)

    self.assertEqual(200, respdata.status_code)

    resp = respdata.json
    self.assertEqual(0, resp['code'], respdata.data)
    self.assertIsNotNone(resp['data'], respdata.data)

Это тест загрузки списка домашней страницы, который относительно прост.

0x03 Сводка

В процессе разработки проекта повторяющаяся логика должнаабстрактная инкапсуляция

Don't repeat yourself

А то, как инкапсулировать, зависит от личных навыков.Я думаю, что нет почти никакого пути, кроме как узнать больше и посмотреть исходный код.

0x04 Учебные материалы