# Service Worker 正在成为浏览器的“隐形服务器”

Simon Willison 在 2026 年 5 月 30 日发了一篇文章,标题平淡无奇——“Running Python ASGI apps in the browser with Pyodide and Service Workers”。没有震惊,没有颠覆。但读完后,你会意识到他做了一件此前几乎没人认真实现过的事:用 Service Worker 把整个 Python 后端装进了浏览器。
他借助的是 Claude Opus 4.8。
一、一个被严重低估的浏览器 API

先说 Service Worker 是什么。
大多数开发者对 Service Worker 的印象停留在两个场景:PWA 离线缓存,和消息推送。它像一个躲在浏览器后台的老黄牛,注册一下 Service Worker,把静态资源缓存起来,然后就能离线访问了。
这个印象,严重低估了 Service Worker 的能力。
Service Worker 实际上运行在浏览器的网络层。它可以拦截所有同源的网络请求,包括 fetch() 发出的请求。当它拦截到一个请求,它可以做什么?它可以不发出这个请求,然后用任何内容作为响应返回给浏览器。
换句话说:Service Worker 可以在请求发出之前,把它截胡,然后塞给任意一个处理程序,最后假装什么都没发生过地返回结果。
这不是缓存。这是一个真正意义上的浏览器内部中间件。
理解这一点后,你会发现 Service Worker 的能力远不止 PWA 离线缓存。理论上,你可以拦截 /api/* 的请求,把它们发给浏览器里运行的任意逻辑处理,然后用处理结��作为响应返回。整个过程,浏览器毫不知情,它只知道收到了一条来自同源的 Response。
这就是 Simon Willison 那个方案的核心思路。
二、Web Worker 四年没能解决的问题
在 2022 年,Simon Willison 就启动了 Datasette Lite 项目——一个把 Datasette(他做的 SQLite 可视化工具)完全跑在浏览器里的尝试。
当时的技术方案是用 Web Worker 加载 Pyodide。Pyodide 负责运行 Python 代码,Datasette 负责处理数据库查询和页面渲染,然后生成好的 HTML 通过 fetch 传给主线程显示。
这个方案跑通了。但有一个致命缺陷:$(document).ready() 这类 jQuery 事件不触发,