Skip to content

Commit 26d7492

Browse files
authored
Add ip location cache (#205)
* Add ip location cache * Fix ip location cache * Fix getting subscripts for offline locations
1 parent 83b6a10 commit 26d7492

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

backend/app/core/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ def validator_api_url(cls, values):
147147
OPERA_LOG_ENCRYPT: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ******
148148
OPERA_LOG_ENCRYPT_INCLUDE: list[str] = ['password', 'old_password', 'new_password', 'confirm_password']
149149

150+
# ip location
151+
IP_LOCATION_REDIS_PREFIX: str = 'fba_ip_location'
152+
IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
153+
150154
class Config:
151155
# https://docs.pydantic.dev/usage/settings/#dotenv-env-support
152156
env_file = '.env'

backend/app/utils/request_parse.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from user_agents import parse
88

99
from backend.app.common.log import log
10+
from backend.app.common.redis import redis_client
1011
from backend.app.core.conf import settings
1112
from backend.app.core.path_conf import IP2REGION_XDB
1213

@@ -47,7 +48,7 @@ async def get_location_online(ip: str, user_agent: str) -> dict | None:
4748

4849

4950
@sync_to_async
50-
def get_location_offline(ip: str) -> list[str] | None:
51+
def get_location_offline(ip: str) -> dict | None:
5152
"""
5253
离线获取 ip 地址属地,无法保证准确率,100%可用
5354
@@ -59,8 +60,12 @@ def get_location_offline(ip: str) -> list[str] | None:
5960
searcher = XdbSearcher(contentBuff=cb)
6061
data = searcher.search(ip)
6162
searcher.close()
62-
location_info = data.split('|')
63-
return location_info
63+
data = data.split('|')
64+
return {
65+
'country': data[0] if data[0] != '0' else None,
66+
'regionName': data[2] if data[2] != '0' else None,
67+
'city': data[3] if data[3] != '0' else None,
68+
}
6469
except Exception as e:
6570
log.error(f'离线获取 ip 地址属地失败,错误信息:{e}')
6671
return None
@@ -69,18 +74,22 @@ def get_location_offline(ip: str) -> list[str] | None:
6974
async def parse_ip_info(request: Request) -> tuple[str, str, str, str]:
7075
country, region, city = None, None, None
7176
ip = await get_request_ip(request)
77+
location = await redis_client.get(f'{settings.IP_LOCATION_REDIS_PREFIX}:{ip}')
78+
if location:
79+
country, region, city = location.split(' ')
80+
return ip, country, region, city
7281
if settings.LOCATION_PARSE == 'online':
7382
location_info = await get_location_online(ip, request.headers.get('User-Agent'))
74-
if location_info:
75-
country = location_info.get('country')
76-
region = location_info.get('regionName')
77-
city = location_info.get('city')
7883
elif settings.LOCATION_PARSE == 'offline':
7984
location_info = await get_location_offline(ip)
80-
if location_info:
81-
country = location_info[0] if location_info[0] != '0' else None
82-
region = location_info[2] if location_info[2] != '0' else None
83-
city = location_info[3] if location_info[3] != '0' else None
85+
else:
86+
location_info = None
87+
if location_info:
88+
country = location_info.get('country')
89+
region = location_info.get('regionName')
90+
city = location_info.get('city')
91+
await redis_client.set(f'{settings.IP_LOCATION_REDIS_PREFIX}:{ip}', f'{country} {region} {city}',
92+
ex=settings.IP_LOCATION_EXPIRE_SECONDS)
8493
return ip, country, region, city
8594

8695

0 commit comments

Comments
 (0)