我正在工作于一个名为FarmConnect的大型农业平台,该平台运行在Ubuntu 24.04上,使用Docker Compose。

环境

  • Ubuntu 24.04
  • Docker Compose
  • Node.js 22
  • React + Vite前端
  • PostgreSQL
  • Redis
  • Kafka(KRaft模式)
  • Keycloak
  • APISIX网关
  • Tailscale公共访问
  • 应用程序容器:farmconnect/api:latest

目标

我试图让第一个工作流程工作:

快速农民注册

一名现场代理填写表格,应用程序应该保存农民本地(离线优先)使用浏览器中的SQLite WASM并稍后同步。

当前症状

当提交表单时,我收到以下错误:

错误:本地注册不可用:initialized=false,db=false,user=true

用户已成功认证:

localStorage.getItem("auth_token")

{
  userId: 900001,
  email: "[email protected]",
  role: "farmer"
}

所以认证似乎是正常的。

相关代码

QuickFarmerRegistration使用:

const { isInitialized, db } = useDatabase();
const { user } = useAuth();

并在以下位置失败:

if (!isInitialized || !db || !user) {
  throw new Error(
    `Local registration unavailable: initialized=${isInitialized}, db=${!!db}, user=${!!user}`
  );
}

运行时值:

initialized=false
db=false
user=true

我们发现的内容

最初的浏览器控制台显示:

Failed to load SQLite WASM module

Push changes error for farmers
Push changes error for farms
Push changes error for crops
...

已应用的修复

我们发现 sql-wasm.wasm 并未被打包到Docker镜像中。

我修改了Dockerfile:

RUN npm run build
RUN cp node_modules/sql.js/dist/sql-wasm.wasm dist/public/sql-wasm.wasm

重新构建镜像:

docker build --no-cache -t farmconnect/api:latest .
docker compose up -d --force-recreate app

现在WASM文件确实被服务:

curl -I http://localhost:3000/sql-wasm.wasm

返回:

HTTP/1.1 200 OK
Content-Type: application/wasm

通过APISIX:

curl -I https://america.tail3a833f.ts.net/sql-wasm.wasm

也返回:

Content-Type: application/wasm

额外的错误

浏览器仍然显示:

WebSocket连接失败

EventSource's response has a MIME type ("text/html")
that is not "text/event-stream"

这表明某些同步/SSE端点可能在APISIX后面配置不正确。

我的问题

在这种情况下:

  1. WASM文件被正确服务。
  2. 认证工作。
  3. useDatabase() 仍然没有初始化 (initialized=false, db=false)。

我将从哪里继续调查?

  • SQLite WASM初始化代码?
  • 服务工作者/ PWA缓存?
  • CSP限制?
  • Web Worker加载失败?
  • APISIX路由?
  • 其他什么?

最有可能的原因是useDatabase() 永远不会被初始化,即使WASM文件现在是可达的?

> await Promise.all((await navigator.serviceWorker.getRegistrations()).map(r => r.unregister()));

await Promise.all((await caches.keys()).map(k => caches.delete(k)));

localStorage.removeItem("pendingFarmerSubmissions");

indexedDB.deleteDatabase("sqlite-backup");

location.href = "/quick-farmer-registration?fresh=" + Date.now();

< SyntaxError: Unexpected identifier 'Promise'