前言
相关文章
代码
from flask import Flask, send_file, jsonify
import os
import random
import redis
import logging
app = Flask(__name__)
# 配置日志
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 连接 Redis,使用环境变量
redis_client = redis.StrictRedis(
host=os.getenv('REDIS_HOST', 'localhost'),
port=int(os.getenv('REDIS_PORT', 6379)),
db=int(os.getenv('REDIS_DB', 0)),
password=os.getenv('REDIS_PASSWORD', None), # 可选,如果没有密码则为 None
decode_responses=True
)
# 从环境变量获取 API 路径
STATS_PATH = os.getenv('STATS_PATH', '/images/stats')
IMAGE_PATH = os.getenv('IMAGE_PATH', '/images/<image_type>')
# 获取 API 调用统计信息
@app.route(STATS_PATH, methods=['GET'])
def get_stats():
stats = {key: redis_client.get(key) or 0 for key in IMAGE_DIRS.keys()}
logger.info(f'API调用统计信息: {stats}')
return jsonify(stats)
# 读取并配置图片文件夹路径
image_dirs_env = os.getenv('IMAGE_DIRS')
IMAGE_DIRS = {image_type: dir_path for image_type, dir_path in (item.split('=') for item in image_dirs_env.split(','))}
# 读取支持的图片扩展名
image_extensions_env = os.getenv('IMAGE_EXTENSIONS', '.jpg,.jpeg,.png,.webp')
IMAGE_EXTENSIONS = tuple(image_extensions_env.split(',')) # 转换为元组以便使用
# 更新 API 调用计数
def update_api_call_count(api_name):
redis_client.incr(api_name)
logger.info(f'API调用计数更新: {api_name}')
# 获取随机图片
def get_random_image(images_dir):
try:
# 使用环境变量中的扩展名筛选图片
images = [f for f in os.listdir(images_dir) if f.endswith(IMAGE_EXTENSIONS)]
if not images:
logger.warning(f'没有找到图片在目录: {images_dir}')
return jsonify({'error': '没有找到图片'}), 404
random_image = random.choice(images)
logger.info(f'随机选择的图片: {random_image}')
return send_file(os.path.join(images_dir, random_image), mimetype='image/jpeg')
except Exception as e:
logger.error(f'获取随机图片时发生错误: {str(e)}')
return jsonify({'error': str(e)}), 500
# 处理获取随机图片的请求
@app.route(IMAGE_PATH, methods=['GET'])
def random_image(image_type):
logger.info(f'接收到请求获取图片类型: {image_type}')
if image_type not in IMAGE_DIRS:
logger.warning(f'无效的图片类型请求: {image_type}')
return jsonify({'error': '无效的图片类型'}), 400
update_api_call_count(image_type)
response = get_random_image(IMAGE_DIRS[image_type])
response.headers['Cache-Control'] = 'no-store' # 禁用缓存
return response
@app.after_request
def add_no_cache_headers(response):
response.cache_control.no_store = True # 禁用缓存
return response
# 提供 favicon.ico
@app.route('/favicon.ico')
def favicon():
return send_file(os.path.join(app.root_path, 'favicon', 'favicon.ico'), mimetype='image/vnd.microsoft.icon')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
体验地址
仅用作测试,没做整理、图片不多。
制作镜像
相关依赖
创建一个app.py
文件
from flask import Flask, send_file, jsonify
import os
import random
import redis
import logging
app = Flask(__name__)
# 配置日志
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 连接 Redis,使用环境变量
redis_client = redis.StrictRedis(
host=os.getenv('REDIS_HOST', 'localhost'),
port=int(os.getenv('REDIS_PORT', 6379)),
db=int(os.getenv('REDIS_DB', 0)),
password=os.getenv('REDIS_PASSWORD', None), # 可选,如果没有密码则为 None
decode_responses=True
)
# 从环境变量获取 API 路径
STATS_PATH = os.getenv('STATS_PATH', '/images/stats')
IMAGE_PATH = os.getenv('IMAGE_PATH', '/images/<image_type>')
# 获取 API 调用统计信息
@app.route(STATS_PATH, methods=['GET'])
def get_stats():
stats = {key: redis_client.get(key) or 0 for key in IMAGE_DIRS.keys()}
logger.info(f'API调用统计信息: {stats}')
return jsonify(stats)
# 读取并配置图片文件夹路径
image_dirs_env = os.getenv('IMAGE_DIRS')
IMAGE_DIRS = {image_type: dir_path for image_type, dir_path in (item.split('=') for item in image_dirs_env.split(','))}
# 读取支持的图片扩展名
image_extensions_env = os.getenv('IMAGE_EXTENSIONS', '.jpg,.jpeg,.png,.webp')
IMAGE_EXTENSIONS = tuple(image_extensions_env.split(',')) # 转换为元组以便使用
# 更新 API 调用计数
def update_api_call_count(api_name):
redis_client.incr(api_name)
logger.info(f'API调用计数更新: {api_name}')
# 获取随机图片
def get_random_image(images_dir):
try:
# 使用环境变量中的扩展名筛选图片
images = [f for f in os.listdir(images_dir) if f.endswith(IMAGE_EXTENSIONS)]
if not images:
logger.warning(f'没有找到图片在目录: {images_dir}')
return jsonify({'error': '没有找到图片'}), 404
random_image = random.choice(images)
logger.info(f'随机选择的图片: {random_image}')
return send_file(os.path.join(images_dir, random_image), mimetype='image/jpeg')
except Exception as e:
logger.error(f'获取随机图片时发生错误: {str(e)}')
return jsonify({'error': str(e)}), 500
# 处理获取随机图片的请求
@app.route(IMAGE_PATH, methods=['GET'])
def random_image(image_type):
logger.info(f'接收到请求获取图片类型: {image_type}')
if image_type not in IMAGE_DIRS:
logger.warning(f'无效的图片类型请求: {image_type}')
return jsonify({'error': '无效的图片类型'}), 400
update_api_call_count(image_type)
response = get_random_image(IMAGE_DIRS[image_type])
response.headers['Cache-Control'] = 'no-store' # 禁用缓存
return response
@app.after_request
def add_no_cache_headers(response):
response.cache_control.no_store = True # 禁用缓存
return response
# 提供 favicon.ico
@app.route('/favicon.ico')
def favicon():
return send_file(os.path.join(app.root_path, 'favicon', 'favicon.ico'), mimetype='image/vnd.microsoft.icon')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
创建一个rely.txt
文件,添加下面内容
Flask>=2.0.3
Werkzeug>=2.0.3
redis>=4.0.2
gunicorn
创建一个favicon
文件夹,将favicon.ico放进去
mkdir favicon
创建dockerfile
文件
# 使用官方 Python 镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /usr/src/app
# 复制项目文件
COPY . .
# 安装依赖
RUN pip install --no-cache-dir --timeout=300 -r requirements.txt
# 设置时区
ENV TZ=Asia/Shanghai
# 设置环境变量(可不填,构建容器写入即可。)
ENV REDIS_HOST=
ENV REDIS_PORT=
ENV REDIS_DB=0
ENV REDIS_PASSWORD=
# 暴露端口
EXPOSE 5000
# 启动应用
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]
构建镜像
docker build -t random-image-api .
构建容器
参数
IMAGE_DIRS:分类=容器文件路径(必有参数)
例:IMAGE_DIRS=pixiv=images/pixiv
REDIS_HOST:redis地址(可选参数,默认:localhost
)
例:REDIS_HOST=127.0.0.1
REDIS_PORT:redis端口(可选参数,默认:6379
)
例:REDIS_PORT=6379
REDIS_DB:redis号库(可选参数,默认0号库)
例:REDIS_DB=2
REDIS_PASSWORD:redis密码(可选参数,默认:None
)
例:REDIS_PASSWORD=REDIS_PASSWORD
IMAGE_EXTENSIONS:图片类型(可选参数,默认:.jpg,.jpeg,.png,.webp
)
例:IMAGE_EXTENSIONS=.jpg,.jpeg,.png,.webp,.gif,.bmp
STATS_PATH:统计API访问路径(可选参数,默认:/images/stats
)
例:STATS_PATH=/images/stats
访问路径:域名/images/stats
IMAGE_PATH:随机图API访问路径(可选参数,默认:/images/<image_type>
,其中<image_type>
为必须携带参数且在末尾)
例:IMAGE_PATH=/images/<image_type>
访问路径:域名/images/pixiv,此处的<image_type>
为IMAGE_DIRS=pixiv=images/pixiv
中左侧的pixiv
docker run \
-p 5000:5000 \
-v /images-path/pixiv:/usr/src/app/images/pixiv \
-e IMAGE_DIRS=pixiv=images/pixiv \
random-image-api
问题
目前统计会出现图片只出现一次,但后台统计多次的情况。
实测虽然前台只请求一次,但实际请求多次,暂无法解决。
评论区