杰瑞科技汇

Python如何导入OpenResty?

Python 并不能像导入一个普通库(如 import requests)那样直接 "导入" OpenResty 的核心。

OpenResty 是一个基于 Nginx 和 Lua 的 Web 平台,它的核心是 Nginx,并用 Lua 语言扩展了其功能,当你在 Python 环境中谈论 "导入 OpenResty" 时,你通常指的是以下两种情况之一:

  1. 通过 HTTP/REST API 与运行中的 OpenResty 服务交互:这是最常见、最标准的方式,你的 Python 应用程序作为一个客户端,向 OpenResty 暴露的 API 发送请求。
  2. 在 OpenResty 的 Lua 环境中嵌入和执行 Python 代码:这是一种更高级、更复杂的集成方式,通常用于在 Nginx 请求处理流程中直接调用 Python 脚本。

下面我们分别详细讲解这两种方法。


通过 HTTP/REST API 与 OpenResty 交互(推荐)

这是最常用、最灵活的方式,你的 OpenResty 应用(通过 Lua 编写)会提供一个或多个 API 端点,然后你的 Python 程序使用标准的 HTTP 客户端库(如 requests)来调用这些 API。

场景示例

假设你有一个 OpenResty 服务,它监听在 http://localhost:8080,并提供了以下 API:

  • GET /api/hello: 返回一个欢迎信息。
  • POST /api/process_data: 接收 JSON 数据,处理后返回结果。

步骤 1:在 OpenResty (Lua) 中创建 API

你需要使用 OpenResty 的 lua-resty-httpngx.location.capture 等模块来创建 API,这里我们使用 lua-resty-http 来创建一个简单的后端服务,供 Python 调用。

假设你有一个 OpenResty 的配置文件 nginx.conf,其中包含如下 location 块:

http {
    # ... 其他配置 ...
    server {
        listen 8080;
        location /api/hello {
            default_type 'application/json';
            content_by_lua_block {
                -- 简单返回 JSON
                ngx.say('{"message": "Hello from OpenResty!", "timestamp": ', ngx.time(), '}')
                ngx.exit(200)
            }
        }
        location /api/process_data {
            content_by_lua_block {
                -- 获取 POST 请求体
                ngx.req.read_body()
                local data = ngx.req.get_body_data()
                -- 模拟数据处理
                local processed_data = string.upper(data)
                -- 返回处理后的结果
                ngx.say('{"original": "', data, '", "processed": "', processed_data, '"}')
                ngx.exit(200)
            }
        }
    }
}

步骤 2:在 Python 中调用 API

我们可以在 Python 中使用 requests 库来调用上面定义的 API。

安装 requests

pip install requests

编写 Python 脚本

import requests
import json
# OpenResty 服务的地址
BASE_URL = "http://localhost:8080"
def call_hello_api():
    """调用 GET /api/hello 接口"""
    try:
        response = requests.get(f"{BASE_URL}/api/hello")
        response.raise_for_status()  # 如果请求失败 (状态码非 200), 则抛出异常
        # 解析 JSON 响应
        data = response.json()
        print("成功调用 /api/hello:")
        print(json.dumps(data, indent=4, ensure_ascii=False))
    except requests.exceptions.RequestException as e:
        print(f"调用 /api/hello 失败: {e}")
def call_process_data_api(text_to_process):
    """调用 POST /api/process_data 接口"""
    try:
        # 准备请求数据
        payload = {"data": text_to_process}
        # 发送 POST 请求
        response = requests.post(f"{BASE_URL}/api/process_data", json=payload)
        response.raise_for_status()
        # 解析 JSON 响应
        data = response.json()
        print(f"\n成功调用 /api/process_data, 原始数据: '{text_to_process}':")
        print(json.dumps(data, indent=4, ensure_ascii=False))
    except requests.exceptions.RequestException as e:
        print(f"调用 /api/process_data 失败: {e}")
if __name__ == "__main__":
    # 确保 OpenResty 服务正在运行
    call_hello_api()
    call_process_data_api("hello from python")

运行结果:

成功调用 /api/hello:
{
    "message": "Hello from OpenResty!",
    "timestamp": 1678886400
}
成功调用 /api/process_data, 原始数据: 'hello from python':
{
    "original": "hello from python",
    "processed": "HELLO FROM PYTHON"
}

方法一):

  • 优点:解耦性好,Python 和 OpenResty 可以独立部署和扩展,使用标准 HTTP 协议,技术栈成熟。
  • 缺点:存在网络开销,不适合需要极低延迟的内部调用。

在 OpenResty 的 Lua 环境中嵌入 Python 代码

这种方法比较特殊,它允许你在 OpenResty 处理一个 Nginx 请求时,直接在同一个进程中调用 Python 脚本,这通常通过一个第三方 Nginx 模块来实现,最著名的是 ngx_python

⚠️ 重要警告:

  • 复杂性高ngx_python 模块需要你从源码编译 Nginx 和 OpenResty,并将其集成进去,过程非常繁琐。
  • 稳定性:社区支持相对较少,稳定性和性能需要仔细评估。
  • 适用场景:通常用于非常特定的场景,比如需要将遗留的 Python 逻辑无缝集成到 Nginx 请求处理流程中,且对性能要求极高,对于绝大多数项目,不推荐使用此方法

概念流程

  1. 编译安装:你需要下载 ngx_python 模块的源码,然后使用其提供的补丁来重新编译 Nginx/OpenResty。
  2. 配置 Nginx:在 nginx.conf 中配置 ngx_python 模块。
  3. 编写 Lua 代码:在 content_by_lua_block 中,使用 ngx_python 提供的指令来加载和执行 Python 脚本。
  4. 编写 Python 脚本:Python 脚本需要遵循 ngx_python 模块定义的接口规范,以便与 Nginx 的请求环境进行交互(如获取请求头、读取请求体、设置响应等)。

伪代码示例

这只是一个概念演示,实际语法和配置请参考 ngx_python 的官方文档。

Nginx 配置 (nginx.conf)

location /python_handler {
    # 告诉 ngx_python 模块处理这个请求
    python_handler /path/to/your_script.py;
}

Python 脚本 (your_script.py)

# 这个脚本会被 ngx_python 模块加载和执行
# 它需要能访问到 Nginx 的请求对象
def main(ngx):
    # ngx 是一个由模块提供的对象,用于与 Nginx 交互
    # 获取请求头
    user_agent = ngx.request.headers.get('User-Agent')
    # 获取请求体
    request_body = ngx.request.read_body()
    # 设置响应状态码
    ngx.status = 200
    # 设置响应头
    ngx.response.headers['Content-Type'] = 'application/json'
    # 发送响应体
    response_data = {
        "message": "Hello from Python inside OpenResty!",
        "your_ua": user_agent,
        "echo": request_body.decode('utf-8') if request_body else ""
    }
    ngx.response.write(json.dumps(response_data))
# 模块会调用这个 main 函数
main(ngx)

方法二):

  • 优点:性能极高,没有网络开销,集成度最高。
  • 缺点:部署极其复杂,维护困难,生态不成熟,容易引入稳定风险。

结论与建议

特性 方法一 (HTTP API) 方法二 (ngx_python 模块)
易用性 非常高,标准流程 非常低,需要从源码编译
灵活性 非常高,任何能发 HTTP 请求的语言都可以 ,绑定在 Nginx 和 Lua 环境
性能 较好,但有网络开销 极高,进程内调用
稳定性 非常高,技术成熟 一般,依赖第三方模块
适用场景 几乎所有场景,微服务架构,前后端分离 极少数需要极致性能和深度集成的遗留系统整合

给你的建议:

99% 的情况下,你应该选择方法一。

将 OpenResty 作为一个高性能的网关或微服务,通过 REST API 与你的 Python 应用(或其他语言的应用)进行通信,这是现代软件架构的最佳实践,它清晰、健壮且易于维护。

只有在经过充分调研,并且你的项目有非常特殊的高性能需求,且愿意承担其复杂性和维护成本时,才应该考虑方法二。

分享:
扫描分享到社交APP
上一篇
下一篇