优化更新

This commit is contained in:
2026-09-14 14:48:52 +08:00
parent 5e5eef6d14
commit be717f99b7
3 changed files with 47 additions and 49 deletions
+22 -33
View File
@@ -2,14 +2,13 @@
IP地址工具模块 IP地址工具模块
============================================================= =============================================================
提供客户端IP获取和地理位置查询: 提供客户端IP获取功能:
- get_client_ip: 获取客户端真实IP(需配合Flask ProxyFix使用) - get_client_ip: 获取客户端真实IP(支持反向代理场景)
- get_ip_location: 调用第三方API查询IP地理位置
地理位置查询请使用 ip2region 模块(离线数据库,高性能)。
""" """
import json
import logging import logging
import urllib.request
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -18,38 +17,28 @@ def get_client_ip():
""" """
获取客户端真实IP地址 获取客户端真实IP地址
通过Flask ProxyFix中间件由PROXY_NUM配置自动设置 优先级:
request.remote_addr为真实客户端IP。未配置ProxyFix时, 1. X-Forwarded-For 头(反向代理场景,取第一个非内网IP)
request.remote_addr即为直连IP,避免客户端伪造。 2. X-Real-IP 头(Nginx 常用配置)
3. remote_addr(直连场景)
Returns: Returns:
str: 客户端IP地址 str: 客户端IP地址
""" """
from flask import request from flask import request
# 优先从 X-Forwarded-For 获取(反向代理场景)
forwarded_for = request.headers.get("X-Forwarded-For", "")
if forwarded_for:
# 格式: client, proxy1, proxy2 → 取第一个
first_ip = forwarded_for.split(",")[0].strip()
if first_ip and first_ip not in ("127.0.0.1", "localhost", "0.0.0.0", "::1"):
return first_ip
# 回退到 X-Real-IP(Nginx proxy_set_header X-Real-IP $remote_addr)
real_ip = request.headers.get("X-Real-IP", "").strip()
if real_ip and real_ip not in ("127.0.0.1", "localhost", "0.0.0.0", "::1"):
return real_ip
# 最后使用 remote_addr
return request.remote_addr return request.remote_addr
def get_ip_location(ip: str) -> str:
"""
根据IP获取地理位置(使用第三方API)
Args:
ip: IP地址
Returns:
地理位置信息,格式:"国家 省份 城市"
"""
if ip in ['127.0.0.1', 'localhost'] or ip.startswith('192.168.') or ip.startswith('10.'):
return "内网IP"
try:
url = f"http://ip-api.com/json/{ip}?lang=zh-CN"
with urllib.request.urlopen(url, timeout=3) as response:
data = json.loads(response.read().decode('utf-8'))
if data.get('status') == 'success':
return f"{data.get('country', '')} {data.get('regionName', '')} {data.get('city', '')}"
except Exception as e:
logger.warning(f"获取IP地理位置失败: {e}")
return "未知"
+1 -1
View File
@@ -68,7 +68,7 @@ from flask_redis import FlaskRedis
# FlaskRedis 扩展实例 # FlaskRedis 扩展实例
# ============================================================ # ============================================================
# 在应用工厂中通过 init_redis(app) 完成绑定 # 在应用工厂中通过 init_redis(app) 完成绑定
redis_client = FlaskRedis(decode_responses=True, protocol=2) redis_client = FlaskRedis(decode_responses=True)
def init_redis(app: Flask): def init_redis(app: Flask):
+24 -15
View File
@@ -135,8 +135,11 @@ def register_operation_log(app):
1. 请求方法为 POST/PUT/DELETE/PATCH 1. 请求方法为 POST/PUT/DELETE/PATCH
2. 路径不在排除列表中 2. 路径不在排除列表中
3. HTTP 状态码为 2xx 3. HTTP 状态码为 2xx
4. 业务 code 为 0(成功) 4. 非内部调用
5. 非内部调用
记录范围:
- 成功操作(code=0):status=0(正常)
- 失败操作(code!=0,如演示环境拦截):status=1(异常),记录错误信息
""" """
# 只记录写操作 # 只记录写操作
if request.method not in ("POST", "PUT", "DELETE", "PATCH"): if request.method not in ("POST", "PUT", "DELETE", "PATCH"):
@@ -147,24 +150,28 @@ def register_operation_log(app):
if _is_excluded_path(path): if _is_excluded_path(path):
return response return response
# 只记录成功操作(HTTP 2xx 且业务 code=0) # HTTP 非 2xx 不记录(如 404、500 等)
if not (200 <= response.status_code < 300): if not (200 <= response.status_code < 300):
return response return response
try:
data = response.get_json(silent=True)
if data and data.get("code", 0) != 0:
return response
except Exception:
pass
# 内部调用不记录 # 内部调用不记录
if getattr(g, "_internal_call", False): if getattr(g, "_internal_call", False):
return response return response
# 异步记录,不阻塞响应 # 判断业务状态:code=0 为成功,其他为失败
status = 0 # 默认成功
error_msg = ""
try: try:
_write_log(response) data = response.get_json(silent=True)
if data and data.get("code", 0) != 0:
status = 1 # 业务失败
error_msg = data.get("msg", "操作失败")
except Exception:
pass
# 记录日志(成功和失败都记录)
try:
_write_log(response, status=status, error_msg=error_msg)
except Exception as e: except Exception as e:
logger.warning(f"记录操作日志失败: {str(e)}") logger.warning(f"记录操作日志失败: {str(e)}")
@@ -173,7 +180,7 @@ def register_operation_log(app):
logger.info("操作日志中间件注册成功") logger.info("操作日志中间件注册成功")
def _write_log(response): def _write_log(response, status=0, error_msg=""):
""" """
写入操作日志 写入操作日志
@@ -181,6 +188,8 @@ def _write_log(response):
Args: Args:
response: Flask 响应对象 response: Flask 响应对象
status: 操作状态(0-正常,1-异常)
error_msg: 错误信息(失败时)
""" """
from src.core.security import get_username from src.core.security import get_username
from src.common.utils.ip import get_client_ip from src.common.utils.ip import get_client_ip
@@ -217,7 +226,7 @@ def _write_log(response):
title=title, title=title,
log_type=log_type, log_type=log_type,
source=0, # OperationLog.Source.ADMIN source=0, # OperationLog.Source.ADMIN
status=0, # OperationLog.Status.NORMAL status=status,
method=request.endpoint or "", method=request.endpoint or "",
request_method=request.method, request_method=request.method,
url=request.path, url=request.path,
@@ -228,7 +237,7 @@ def _write_log(response):
os=ua_info.get("os", "未知"), os=ua_info.get("os", "未知"),
browser=ua_info.get("browser", "未知"), browser=ua_info.get("browser", "未知"),
consume_time=consume_time, consume_time=consume_time,
error="", error=error_msg,
username=username, username=username,
) )