master
jinql 2025-09-05 23:09:25 +08:00
parent 407c803550
commit d6696ff765
7 changed files with 24 additions and 60 deletions

View File

@ -11,7 +11,7 @@ bind = "0.0.0.0:8000"
workers = 2
# 工作模式sync、gevent、uvicorn.workers.UvicornWorker
worker_class = "uvicorn.workers.UvicornWorker"
worker_class = "uvicorn_worker.UvicornWorker"
# 日志目录
log_dir = Path("logs")
@ -34,7 +34,7 @@ accesslog = "logs/access.log"
errorlog = "-"
# access_log_format 仅在 同步 worker 下有效UvicornWorker下不可用以 YAML 配置优先
# access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
raw_env = [
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
]
@ -44,9 +44,3 @@ timeout = 120
# Keep-Alive超时
keepalive = 5
# 进程名ps aux 中显示)
# proc_name = "gunicorn"
# 守护进程运行(后台运行,默认 False
# daemon = True

View File

@ -11,7 +11,7 @@ bind = "0.0.0.0:8000"
workers = 2
# 工作模式sync、gevent、uvicorn.workers.UvicornWorker
worker_class = "uvicorn.workers.UvicornWorker"
worker_class = "uvicorn_worker.UvicornWorker"
# 日志目录
log_dir = Path("logs")
@ -34,7 +34,7 @@ accesslog = "logs/access.log"
errorlog = "-"
# access_log_format 仅在 同步 worker 下有效UvicornWorker下不可用以 YAML 配置优先
# access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
raw_env = [
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
]
@ -44,9 +44,3 @@ timeout = 120
# Keep-Alive超时
keepalive = 5
# 进程名ps aux 中显示)
# proc_name = "gunicorn"
# 守护进程运行(后台运行,默认 False
# daemon = True

View File

@ -311,10 +311,10 @@ class Favicon:
Returns:
域名是否合法且非内网地址
"""
return _check_internal(domain) and _pattern_domain.match(domain)
return Favicon.check_internal(domain) and _pattern_domain.match(domain)
@staticmethod
def _check_internal(domain: str) -> bool:
def check_internal(domain: str) -> bool:
"""检查网址是否非内网地址
Args:
@ -348,27 +348,4 @@ _pattern_domain = re.compile(
def _check_url(domain: str) -> Optional[Any]:
return _check_internal(domain) and _pattern_domain.match(domain)
def _check_internal(domain: str) -> bool:
"""
检查网址是否非内网地址
Args:
domain:
Returns: True 非内网False 是内网/无法解析
"""
try:
if domain.replace('.', '').isdigit():
return not ipaddress.ip_address(domain).is_private
else:
ips = socket.getaddrinfo(domain, None)
for ip_info in ips:
ip = ip_info[4][0]
if '.' in ip:
return not ipaddress.ip_address(ip).is_private
return True
except Exception as e:
print(f"解析网址出错: {e}")
return False
return Favicon.check_internal(domain) and _pattern_domain.match(domain)

View File

@ -344,7 +344,7 @@ class FaviconService:
with self._lock:
if entity.domain in self.domain_list:
self.domain_list.remove(entity.domain)
# 同时从两个队列中移除元素(处理完成)
# 任务完成,从两个队列中移出元素
self._queue_pull(True, self.icon_queue)
self._queue_pull(True, self.total_queue)
@ -401,7 +401,8 @@ class FaviconService:
if _cached and not cached_icon:
# 缓存已过期,后台刷新缓存
logger.info(f"缓存已过期,加入后台队列刷新: {entity.domain}")
# 只增加总队列计数,不增加实时队列计数(后台任务)
# 开始图标处理,加入两个队列
self.icon_queue.put(entity.domain)
self.total_queue.put(entity.domain)
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
@ -415,31 +416,33 @@ class FaviconService:
if not is_sync:
# 返回默认图片并加入后台队列
logger.info(f"返回默认图片并加入后台队列: {entity.domain}")
# 只增加总队列计数,不增加实时队列计数(后台任务)
# 开始图标处理,加入两个队列
self.icon_queue.put(entity.domain)
self.total_queue.put(entity.domain)
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
return self.get_default(0)
return self.get_default()
else:
# 没有缓存,实时处理,检查队列大小
queue_size = self.icon_queue.qsize()
if queue_size >= self.MAX_QUEUE_SIZE:
# 加入后台队列并返回默认图片
logger.info(f"队列大小({queue_size})>={self.MAX_QUEUE_SIZE},返回默认图片并加入后台队列: {entity.domain}")
# 只增加总队列计数,不增加实时队列计数(后台任务)
# 开始图标处理,加入两个队列
self.icon_queue.put(entity.domain)
self.total_queue.put(entity.domain)
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
return self.get_default(0)
return self.get_default()
else:
# 队列<MAX_QUEUE_SIZE实时处理
logger.info(f"队列大小({queue_size})<{self.MAX_QUEUE_SIZE},实时处理: {entity.domain}")
# 同时增加两个队列计数(实时处理任务)
# 开始图标处理,加入两个队列
self.icon_queue.put(entity.domain)
self.total_queue.put(entity.domain)
icon_content = self.get_icon_sync(entity, _cached)
if not icon_content:
# 获取失败,返回默认图标,不缓存
return self.get_default(0)
return self.get_default()
# 确定内容类型和缓存时间
content_type = filetype.guess_mime(icon_content) if icon_content else ""
@ -451,7 +454,7 @@ class FaviconService:
except Exception as e:
logger.error(f"处理图标请求时发生错误 {url}: {e}")
# 返回默认图标
return self.get_default(0)
return self.get_default()
def get_header(self, content_type: str, cache_time: int = None) -> dict:
return self._get_header(content_type, cache_time)

View File

@ -30,13 +30,10 @@ app.include_router(favicon_router)
@app.middleware("http")
async def log_referer(request: Request, call_next):
_flag = True if ('/icon' in request.url.path and 'url=' in request.url.query) else False
logger.info('#' * 60) if _flag else None
referer = request.headers.get('referrer') or request.headers.get('referer')
if referer:
FileUtil.write_file(referer_log_file, referer, mode='a', atomic=True)
_referrer = request.headers.get('referrer') or request.headers.get('referer')
if _referrer:
FileUtil.write_file(referer_log_file, '%s\n' % _referrer, mode='a')
response = await call_next(request)
logger.info('#' * 60) if _flag else None
return response

View File

@ -8,4 +8,5 @@ beautifulsoup4~=4.13.5
lxml~=6.0.1
PyYAML~=6.0.2
uvicorn~=0.35.0
uvicorn-worker~=0.3.0
gunicorn~=23.0.0

4
run.py
View File

@ -7,10 +7,8 @@ if __name__ == "__main__":
"main:app",
host="127.0.0.1",
port=8000,
reload=False,
reload=True,
log_level="info",
# log_level="warning",
workers=1,
)
server = uvicorn.Server(config)
server.run()