обо мне
Небольшой программист в мире программирования, в настоящее время работает руководителем команды в предпринимательской команде.Стек технологий включает 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 Учебные материалы
-
palletsprojects.com/p/flask/
flask
официальная документация -
docs.SQL alchemy.org/en/13/ORM/ нет…
models
Документация по реляционному отображению -
GitHub.com/ и Linux1024…
Исходный код этого проекта