feat: ADRF async views (phase1) + native async serializers (phase2) + async cache infra
This commit is contained in:
+23
-25
@@ -1,7 +1,10 @@
|
||||
import requests
|
||||
import asyncio
|
||||
|
||||
import aiohttp
|
||||
from asgiref.sync import sync_to_async
|
||||
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from adrf.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
@@ -62,7 +65,7 @@ class GetIPDataView(APIView):
|
||||
502: openapi.Response(description="第三方服务异常"),
|
||||
}
|
||||
)
|
||||
def get(self, request):
|
||||
async def get(self, request):
|
||||
# 获取要查询的IP地址
|
||||
ip = request.GET.get('ip', '').strip()
|
||||
if not ip:
|
||||
@@ -74,7 +77,7 @@ class GetIPDataView(APIView):
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return self._fetch_ip_location(ip)
|
||||
return await self._fetch_ip_location(ip)
|
||||
|
||||
def _get_client_ip(self, request):
|
||||
"""
|
||||
@@ -96,14 +99,14 @@ class GetIPDataView(APIView):
|
||||
|
||||
return None
|
||||
|
||||
def _fetch_ip_location(self, ip):
|
||||
async def _fetch_ip_location(self, ip):
|
||||
"""
|
||||
调用 ip-api.com 获取IP地理信息,支持Redis缓存
|
||||
调用 ip-api.com 获取IP地理信息,支持Redis缓存(全异步:aiohttp + sync_to_async 缓存兜底)
|
||||
"""
|
||||
cache_key = f"ip_location:{ip}"
|
||||
|
||||
# 先尝试从缓存获取
|
||||
cached_data = default_cache.get(cache_key)
|
||||
# 先尝试从缓存获取(django-redis 为同步客户端,用 sync_to_async 兜底)
|
||||
cached_data = await sync_to_async(default_cache.get)(cache_key)
|
||||
if cached_data:
|
||||
return Response(
|
||||
{"code": 200, "message": "success", "data": cached_data},
|
||||
@@ -112,15 +115,15 @@ class GetIPDataView(APIView):
|
||||
|
||||
try:
|
||||
url = IP_API_URL.format(ip=ip)
|
||||
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
||||
|
||||
if response.status_code != 200:
|
||||
return Response(
|
||||
{"code": 502, "message": "IP定位服务异常,请稍后重试", "data": None},
|
||||
status=status.HTTP_502_BAD_GATEWAY
|
||||
)
|
||||
|
||||
result = response.json()
|
||||
timeout = aiohttp.ClientTimeout(total=REQUEST_TIMEOUT)
|
||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||
async with session.get(url) as resp:
|
||||
if resp.status != 200:
|
||||
return Response(
|
||||
{"code": 502, "message": "IP定位服务异常,请稍后重试", "data": None},
|
||||
status=status.HTTP_502_BAD_GATEWAY
|
||||
)
|
||||
result = await resp.json()
|
||||
|
||||
if result.get('status') != 'success':
|
||||
return Response(
|
||||
@@ -139,24 +142,19 @@ class GetIPDataView(APIView):
|
||||
'timezone': result.get('timezone', ''),
|
||||
}
|
||||
|
||||
# 写入缓存
|
||||
default_cache.set(cache_key, ip_info, IP_CACHE_TIMEOUT)
|
||||
# 写入缓存(sync_to_async 兜底)
|
||||
await sync_to_async(default_cache.set)(cache_key, ip_info, IP_CACHE_TIMEOUT)
|
||||
|
||||
return Response(
|
||||
{"code": 200, "message": "success", "data": ip_info},
|
||||
status=status.HTTP_200_OK
|
||||
)
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
except (aiohttp.ClientError, asyncio.TimeoutError):
|
||||
return Response(
|
||||
{"code": 502, "message": "请求超时,请稍后重试", "data": None},
|
||||
status=status.HTTP_502_BAD_GATEWAY
|
||||
)
|
||||
except requests.exceptions.ConnectionError:
|
||||
return Response(
|
||||
{"code": 502, "message": "网络连接异常,请检查网络后重试", "data": None},
|
||||
status=status.HTTP_502_BAD_GATEWAY
|
||||
)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{"code": 500, "message": f"服务器内部错误:{str(e)}", "data": None},
|
||||
|
||||
Reference in New Issue
Block a user