课程 11:通过 Flask API 提供 Redis 数据

本课程基于您已有的 Flask 和 Redis 知识。我们将创建一个 Flask API,用于提供存储在 Redis 数据库中的数据,例如来自数据处理作业的结果(如课程 9 中的词频统计)或其他应用程序数据。

1. 回顾:Flask 和 Redis 基础

让我们快速回顾一下先前课程中的关键概念:

Flask (来自课程 10):

  • 应用程序设置: app = Flask(__name__)
  • 路由:使用像 @app.route('/path') 这样的装饰器将 URL 映射到视图函数。
  • 视图函数:处理请求并返回响应的 Python 函数。
  • JSON 响应:使用 jsonify() 将数据发送回 API 客户端。
  • 运行:使用 app.run(debug=True) 启动开发服务器。

Redis (来自课程 8 & 9):

  • 连接:使用 redis-py 库:r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
  • 数据操作:
    • 字符串:r.set(key, value), r.get(key)
    • 哈希:r.hmset(name, mapping)r.hset(name, key, value), r.hgetall(name), r.hget(name, key)
  • 运行 Redis:通常作为服务运行或通过 Docker 运行(例如 docker run -d -p 6379:6379 redis:alpine)。

2. 集成 Flask 与 Redis

要在 Flask 应用程序中使用 Redis,您需要建立与 Redis 服务器的连接。

在 Flask 中初始化 Redis 连接

对于简单的应用程序,您可以将 Redis 连接初始化为全局变量。当 Flask 应用启动时,此连接将可供您的视图函数使用。

from flask import Flask, jsonify
import redis

app = Flask(__name__)

# 初始化 Redis 连接
try:
    redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    redis_client.ping() # 验证连接
    print("成功连接到 Redis!") # "Successfully connected to Redis!"
except redis.exceptions.ConnectionError as e:
    print(f"无法连接到 Redis: {e}") # "Could not connect to Redis:"
    # 在实际应用中,您可能希望退出或禁用依赖 Redis 的功能
    redis_client = None 

# ... 您的路由和视图函数将在此处定义 ...

对于更大、更复杂的应用程序,管理连接可能涉及使用 Flask 扩展(如 Flask-Redis)或将连接设置集成到应用程序工厂模式中,以更稳健地处理配置和测试。

为 Redis 数据设计 API 端点

在设计用于提供 Redis 数据的 API 端点时:

  • 在适当的情况下遵循 RESTful 原则(例如,使用 GET 检索数据)。
  • 考虑您要公开哪些数据以及客户端将如何查询它(例如,通过特定键,某种类型的所有键)。
  • 为在 Redis 中未找到数据的情况实现错误处理。返回 404 Not Found HTTP 状态码是标准做法。

3. 实践示例:用于 Redis 数据的 Flask API

让我们构建一个 Flask API,用于提供词频统计数据(类似于我们在课程 9 中生成的)和存储在 Redis 中的一些简单用户数据。

前提条件:

  • 已安装 Python 3。
  • 已安装 Flask 和 redis-py 库:pip install Flask redis
  • 一个正在运行的 Redis 实例。您可以使用 Docker 启动一个:
    docker run -d -p 6379:6379 --name my-redis-api-store redis:alpine

步骤 1:用示例数据填充 Redis (可选助手脚本)

如果 Redis 中还没有先前练习的数据,可以创建一个 Python 脚本(例如 `populate_redis_for_api.py`)来放入一些数据。在启动 Flask 应用之前运行此脚本一次。

# populate_redis_for_api.py
import redis

try:
    r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    r.ping() # 检查连接

    # 词频统计示例数据 (可以来自课程 9 或类似)
    word_counts_data = {'spark': 15, 'flask': 10, 'redis': 20, 'api': 12, 'python': 25}
    # 如果您的 redis-py 版本较旧或直接使用字典,可以使用 HMSET
    # 对于 redis-py 4.x 及更高版本, HMSET 已弃用, 请使用带 mapping 参数的 HSET
    if hasattr(r, 'hmset'):
         r.hmset('api_word_counts', word_counts_data)
    else:
        r.hset('api_word_counts', mapping=word_counts_data)
    
    print("已在 Redis 中填充 'api_word_counts' 哈希。") # "Populated 'api_word_counts' hash in Redis."

    # 用户数据示例
    r.set('user:profile:1', '{"name": "Alice Smith", "email": "alice@example.com"}')
    r.set('user:profile:2', '{"name": "Bob Johnson", "email": "bob@example.com"}')
    print("已在 Redis 中填充用户个人资料示例。") # "Populated sample user profiles in Redis."

    print("示例数据填充成功。") # "Sample data populated successfully."

except redis.exceptions.ConnectionError as e:
    print(f"无法连接到 Redis 以填充数据: {e}") # "Could not connect to Redis to populate data:"
except Exception as e:
    print(f"Redis 数据填充期间发生错误: {e}") # "An error occurred during Redis population:"

步骤 2:创建 Flask 应用程序

将以下代码另存为 `app_redis_api.py`:

from flask import Flask, jsonify
import redis
import json # 用于解析用户个人资料字符串

app = Flask(__name__)

# 初始化 Redis 连接
try:
    redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    redis_client.ping()
    print("Flask 应用:成功连接到 Redis!") # "Flask App: Successfully connected to Redis!"
except redis.exceptions.ConnectionError as e:
    print(f"Flask 应用:无法连接到 Redis: {e}") # "Flask App: Could not connect to Redis:"
    redis_client = None # 允许应用运行,但依赖 Redis 的路由将优雅地失败

# --- API 端点 ---

@app.route('/')
def home():
    return "欢迎!此 API 提供来自 Redis 的数据。请尝试 /api/wordcounts 或 /api/user/profile/1" # "Welcome! This API serves data from Redis. Try /api/wordcounts or /api/user/profile/1"

@app.route('/api/wordcounts', methods=['GET'])
def get_all_word_counts():
    if not redis_client:
        return jsonify({"error": "Redis 连接不可用"}), 500 # "Redis connection not available"
    
    word_counts = redis_client.hgetall('api_word_counts')
    if word_counts:
        # 将计数值从字符串转换为整数以便正确的 JSON 格式
        word_counts_int = {word: int(count) for word, count in word_counts.items()}
        return jsonify(word_counts_int)
    else:
        return jsonify({"message": "未找到词频统计或键 'api_word_counts' 不存在。"}), 404 # "No word counts found or key 'api_word_counts' does not exist."

@app.route('/api/wordcount/<word>', methods=['GET'])
def get_specific_word_count(word):
    if not redis_client:
        return jsonify({"error": "Redis 连接不可用"}), 500 # "Redis connection not available"
        
    count = redis_client.hget('api_word_counts', word.lower()) # 假设单词以小写形式存储
    if count is not None:
        return jsonify({word: int(count)})
    else:
        return jsonify({"error": f"未找到单词 '{word}'。"}), 404 # "Word '{word}' not found."

@app.route('/api/user/profile/<user_id>', methods=['GET'])
def get_user_profile(user_id):
    if not redis_client:
        return jsonify({"error": "Redis 连接不可用"}), 500 # "Redis connection not available"
        
    profile_json_str = redis_client.get(f'user:profile:{user_id}')
    if profile_json_str:
        try:
            profile_data = json.loads(profile_json_str) # 解析来自 Redis 的 JSON 字符串
            return jsonify(profile_data)
        except json.JSONDecodeError:
            return jsonify({"error": "从 Redis 解码用户个人资料数据失败。"}), 500 # "Failed to decode user profile data from Redis."
    else:
        return jsonify({"error": f"未找到 ID 为 '{user_id}' 的用户个人资料。"}), 404 # "User profile for ID '{user_id}' not found."

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

步骤 3:运行和测试 API

  1. 确保 Redis 正在运行:
    docker ps (应显示您的 Redis 容器,例如 `my-redis-api-store`)。
  2. 填充 Redis (如果尚未操作):
    python populate_redis_for_api.py
  3. 运行 Flask 应用程序:
    python app_redis_api.py
    您应该会看到指示已连接到 Redis 以及 Flask 服务器已启动的消息。
  4. 测试 API 端点 (例如,使用 `curl` 或您的浏览器):
    • 获取所有词频统计:
      curl http://127.0.0.1:5000/api/wordcounts
    • 获取 "spark" 的计数:
      curl http://127.0.0.1:5000/api/wordcount/spark
    • 获取一个不存在的单词的计数:
      curl http://127.0.0.1:5000/api/wordcount/nonexistent
    • 获取用户 1 的个人资料:
      curl http://127.0.0.1:5000/api/user/profile/1
    • 获取一个不存在的用户的个人资料:
      curl http://127.0.0.1:5000/api/user/profile/99

结论

Flask 使得构建能够从包括 Redis 在内的各种来源提供数据的 API 变得简单直接。通过将 Flask 连接到 Redis,您可以快速公开存储在 Redis 内存数据库中的已处理数据、缓存信息或应用程序状态。这种组合对于创建依赖于快速访问动态数据的响应式应用程序非常强大。