workerd Python REPL Server 示例深度解析在 Cloudflare Workers 运行时中搭建 HTTP 驱动的 Python 交互式解释器【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerdworkerd 是驱动 Cloudflare Workers 的 JavaScript / Wasm 运行时而本仓库的samples/repl-server-python示例展示了如何在 workerd 中运行一个基于 Python 的 REPL 服务worker 侧用 Python 内置的code.InteractiveInterpreter逐条执行客户端通过 HTTP POST 发送的 Python 表达式Node.js 侧则以自定义eval的node:repl作为交互前端。本文以该示例文档为骨架结合 worker.py、config.capnp 与 client.js 源码完整讲解其配置、运行方式、实现原理与测试定位帮助读者掌握 workerd Python Workers 的模块装载、兼容性标志与WorkerEntrypoint编程模型。示例定位实验性的 Python 版 REPL Server[samples/repl-server-python/README.md](https://link.gitcode.com/i/730fd378720fd66f1e2ad9474042c420)明确指出该示例创建一个简单的 REPL 服务器通过 HTTP 与 Node.js 客户端通信目前高度实验性very experimental仅用于测试目的。它是samples/repl-serverJavaScript 变体的Python 变体两者使用同一份 Node.js 客户端 client.js只是服务端实现语言不同维度JS 变体samples/repl-serverPython 变体samples/repl-server-pythonWorker 源码worker.js使用workerd:unsafe-eval模块执行 JS 表达式worker.py使用 Python 标准库code.InteractiveInterpreter结果回显通过node:util的util.inspect序列化表达式结果通过重定向sys.stdout捕获print等输出配置差异常规 JS 模块modulesesModulepythonModule embed ./worker.pypython_workers兼容标志理解这一点很关键REPL 服务的核心是「接收命令 → 执行 → 返回输出」JS 版本借助 workerd 提供的workerd:unsafe-eval内建模块完成动态求值Python 版本则借助 Pyodide 在 workerd 内嵌的 CPython 解释器与 Python 自带的交互式解释器工具链完成二者殊途同归。运行方式一条命令起服务一条命令开 REPLREADME 给出的使用方式极简只有两条命令./bazel-bin/src/workerd/server/workerd serve samples/repl-server-python/config.capnp --experimental node samples/repl-server/client.js两条命令的职责拆解如下启动 workerd 服务./bazel-bin/src/workerd/server/workerd serve ...使用 Bazel 构建产物中的workerd可执行文件以serve子命令加载 config.capnp 配置并启动。--experimental标志用于启用实验性能力该示例明确处于实验阶段运行它需要该标志。启动 Node.js REPL 客户端node samples/repl-server/client.js在终端启动一个node:repl交互会话用户输入的任何 Python 代码都会被包装成 JSON 请求发给localhost:8080并把返回文本原样打印。前提条件需要先用 Bazel 构建出workerd二进制bazel build //src/workerd/server:workerd之类并将 Python Workers 支持编译进二进制——这是整个samples/pyodide体系生效的基础。配置文件逐项拆解services、sockets 与 pythonModuleconfig.capnp 使用 workerd 的 Capn Proto 配置格式完整内容如下using Workerd import /workerd/workerd.capnp; const config :Workerd.Config ( services [ (name main, worker .mainWorker), ], sockets [ # Serve HTTP on port 8080. ( name http, address *:8080, http (), service main ), ], ); const mainWorker :Workerd.Worker ( modules [ (name worker.py, pythonModule embed ./worker.py), ], compatibilityDate 2023-12-18, compatibilityFlags [python_workers], # Learn more about compatibility dates at: # https://developers.cloudflare.com/workers/platform/compatibility-dates/ );要点逐条说明services定义一个名为main的服务绑定到mainWorkerworker 定义。WorkerEntrypoint的fetch方法即由此服务对外暴露。sockets监听*:8080所有网卡、8080 端口http ()表示这是一个纯 HTTP 套接字不带 TLS请求转发给main服务。Node.js 客户端正是向http://localhost:8080发起 POST 请求。modules与pythonModule这是 Python Worker 与 JS Worker 的关键差异。JS Worker 使用esModule embed ./worker.js而这里使用pythonModule embed ./worker.py把 Python 源码作为模块内嵌进二进制。embed表示构建时把文件内容打进配置/二进制name worker.py给出模块名。compatibilityDate 2023-12-18声明兼容日期workerd 根据该日期决定启用哪些运行时行为。可对照 compatibility-date 相关源码 了解日期到行为的映射机制。compatibilityFlags [python_workers]启用 Python Workers 能力的关键开关。从源码结构看该标志在整个仓库中被广泛读取——例如 src/pyodide/internal/metadata.ts 会把一组python_*兼容标志透传给 Python 侧运行时python_no_global_handlers、python_dedicated_snapshot等worker-loader.c 与 compatibility-date.c 也都引用了该标志用于决定是否允许装载pythonModule。对比同仓库的 samples/pyodide/config.capnp 可以看到Python 示例的配置骨架完全一致仅在标志上多了python_workers_20250116更新一档的 Python Workers 行为快照进一步印证pythonModulepython_workers是 workerd 装载 Python 模块的标准组合。worker.py 源码剖析用标准库实现远程 Python 求值worker.py 是整个示例的核心完整源码如下import code import sys from io import StringIO from js import Response from workers import WorkerEntrypoint sys.stdout StringIO() ii code.InteractiveInterpreter() class Default(WorkerEntrypoint): async def fetch(self, request): cmd (await request.json()).cmd ii.runsource(cmd) res sys.stdout.getvalue() sys.stdout StringIO() return Response.new(res)逐段解读导入标准库与 workerd 桥接模块code提供 Python 的交互式解释器工具sys/io.StringIO用于输出捕获from js import Response暴露 workerd 的 JSResponse对象给 PythonPyodide 的 JS 互操作层from workers import WorkerEntrypoint引入 workerd 的 Python 入口点基类。全局输出重定向模块加载时就把sys.stdout替换为StringIO()缓冲这样print(...)之类的输出不会落到解释器真实 stdout而是被收集起来。Default(WorkerEntrypoint)与 workers-module.h 中定义的 C 侧WorkerEntrypoint类对应——Python 侧继承它并覆写fetch即成为该 worker 的默认入口。它等价于 JS 侧的export default { async fetch(...) }默认导出。fetch的请求处理await request.json()解析 POST 的 JSON 体并取出cmd字段ii.runsource(cmd)把这段文本喂给code.InteractiveInterpreter执行支持多行代码与语法续行语义随后取出缓冲的 stdout 内容重置缓冲最后Response.new(res)构造 HTTP 响应返回。异步入口注意fetch声明为async def——workerd 的事件循环与 Python 异步模型在此衔接request.json()是异步操作。这种「InteractiveInterpreter.runsourceStringIO捕获 stdout」的模式正是 Python 标准库实现 REPL 的经典做法CPython 的python -i交互式会话底层同样基于code模块示例把它从终端搬到了 HTTP 请求上。Node.js 客户端剖析把 node:repl 变成远程 Python 终端客户端 client.js 并不在 Python 目录下而是与 JS 变体共用const repl require(repl); const myeval async (cmd, ctx, fname, callback) { const res await fetch(http://localhost:8080, { method: POST, headers: { Accept: application/json, Content-Type: application/json }, body: JSON.stringify({cmd}) }); callback(null, await res.text()); } repl.start({ eval: myeval, writer: a a });工作流程repl.start({eval: myeval, writer: a a})启动 Node 自带的 REPL 循环但把默认的求值函数替换为myeval——每次用户在终端输入一行或多行代码myeval就把{cmd}以 JSON 形式 POST 到http://localhost:8080收到响应后通过callback(null, await res.text())把 worker 返回的文本作为 REPL 输出原样呈现。writer: a a表示不对结果做二次格式化直接输出 worker 已格式化好的文本。由此形成完整的交互闭环终端输入 → node:repl 捕获 → HTTP POST → workerd 内 Python 解释器执行 → stdout 捕获 → HTTP 响应 → 终端回显。前端完全无需感知执行引擎是 Python 还是 JavaScript——这也是该示例与samples/repl-server共用同一客户端的根本原因。与 JS 变体的实现对比两种动态求值路径将 worker.jsJS 变体与 worker.py 对照可以更清晰地理解两种运行时的求值策略JS 变体通过import { default as UnsafeEval } from workerd:unsafe-eval获得 workerd 内建的动态求值能力并用node:util的util.inspect把任意表达式结果序列化成可读文本同时覆写console.log把日志吸入缓冲最后拼装consoleLogBuf util.inspect(res, {colors: true})返回。Python 变体依赖 Pyodide 内嵌的 CPython 与标准库code模块输出捕获天然依赖sys.stdout重定向无需自建序列化逻辑。两者都采用「请求体带命令、响应体带输出」的同一协议所以客户端可以共用。这也从侧面说明REPL 服务本质上是把「执行环境」抽象成 HTTP 接口workerd 的 Python 支持让同样的接口模式可以透明地落在 Python 解释器上。实验性质与局限README 反复强调该示例仅用于测试目的。结合实现细节可以看到它的明显边界无状态、单会话每个请求各自调用runsource解释器状态ii虽在模块级共享但客户端每次 REPL 输入的上下文依赖全局状态维持且无鉴权、无并发保护——只适合本地实验。依赖--experimental与兼容标志python_workers标志与--experimental启动参数意味着该能力尚未稳定行为可能随 workerd 版本与兼容日期演进。直接执行任意代码服务会执行客户端传来的任意 Python 代码与 JS 变体一样属于「运行不可信输入」的场景绝不应部署到不可信网络环境。仓库中 src/workerd/server/tests/python/ 下存在大量.wd-test与py_wd_test.bzl驱动的 Python 测试例如python-abort-isolate-on-fatal、vendor_dir_compat_flag说明 Python Workers 能力在 workerd 内部有系统的测试保障而本 REPL 示例同样以「供测试使用」的姿态存在读者可将其视为理解 Python Worker 编程模型的最小可运行样本。延伸阅读samples/pyodide/更常规的 Python Worker 示例展示WorkerEntrypoint的最小 fetch 实现与更完整的兼容标志组合src/pyodide/internal/metadata.tsPython 运行时如何读取 workerd 兼容标志与包信息src/workerd/api/workers-module.hWorkerEntrypoint的 C 侧定义samples/repl-server/worker.jsJS 变体 REPL 的完整实现可与本文 Python 实现对照学习samples/repl-server/README.mdJS 变体的运行说明。【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考