You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyScript open()写入本地JSON文件 刷新后数据丢失问题

核心原因

写入不持久是PyScript的运行机制+浏览器安全限制共同导致的,和你写的用户名重复校验逻辑无关:

  • PyScript基于Pyodide运行在浏览器端独立沙箱中,所有通过<py-env>预加载的文件,页面初始化时都会被复制到内存级虚拟文件系统。你代码里调用open()、json.load()、json.dump()操作的全程都是这份内存里的临时副本,根本没有触碰到磁盘上存储的实体login.json。
  • 现代浏览器有强制安全规则:禁止网页脚本静默读写用户本地磁盘、服务器磁盘上的实体文件。页面刷新或关闭后沙箱内存会被直接回收,所有临时写入的数据自然全部清空。
  • 不存在任何前端侧直接静默写本地实体文件的偏方,所有现代浏览器都封堵了相关能力,不用浪费时间尝试绕限。
实现方案

根据你的使用场景二选一即可,都能实现持久化存储不丢数据。

方案1:部署到Web服务器场景(推荐,符合站点使用逻辑)

不要尝试在前端PyScript代码里直接写服务器上的实体文件,加一层极简的后端接口处理文件读写即可,不需要复杂框架。

  1. 先写极简后端接口(以Python内置FastAPI为例,10行代码即可),负责实际读写服务器上的login.json:
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import json

app = FastAPI()
# 允许前端页面跨域调用
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
USER_FILE = "login.json"

# 读用户数据接口
@app.get("/users")
def get_users():
    with open(USER_FILE, "r", encoding="utf-8") as f:
        return json.load(f)

# 写用户数据接口
@app.post("/register")
def register(username: str, password: str):
    with open(USER_FILE, "r", encoding="utf-8") as f:
        users = json.load(f)
    if username in users:
        raise HTTPException(status_code=400, detail="user already exists")
    users[username] = password
    with open(USER_FILE, "w", encoding="utf-8") as f:
        json.dump(users, f, ensure_ascii=False, indent=2)
    return {"msg": "user created"}
  1. 修改你PyScript里的注册函数,把原来直接操作本地文件的逻辑改成调用上面的后端接口,用PyScript内置的pyfetch发请求即可:
<py-script>
import json
from pyodide.http import pyfetch

async def danm(*args):
    # 获取表单输入值,对应你自己页面的输入框id
    username = Element("username-input").value.strip()
    password = Element("password-input").value.strip()
    if not username or not password:
        print("username and password cannot be empty")
        return
    # 调用注册接口
    try:
        resp = await pyfetch(
            f"/register?username={username}&password={password}",
            method="POST"
        )
        if resp.ok:
            result = await resp.json()
            print(result["msg"])
            # 可在此处加Bootstrap弹窗提示注册成功
        else:
            err = await resp.json()
            print(err["detail"])
            # 可在此处加Bootstrap弹窗提示用户名已存在
    except Exception as e:
        print(f"request error: {str(e)}")

# 绑定注册按钮点击事件,对应你自己页面的按钮id
Element("register-btn").element.addEventListener("click", danm)
</py-script>

注意:提前在后端服务同目录下初始化login.json内容为{},保证接口第一次运行能正常读取;前端表单控件的id要和代码里的选择器一一对应。

方案2:纯本地离线打开页面场景(不需要搭后端)

如果你的页面就是本地双击打开用,不部署到服务器,直接用浏览器内置的localStorage做持久化即可,不需要操作json文件,数据存在浏览器本地存储里,刷新、关闭浏览器再打开都不会丢。修改后的注册函数如下:

<py-script>
import json
from js import localStorage

def danm(*args):
    username = Element("username-input").value.strip()
    password = Element("password-input").value.strip()
    if not username or not password:
        print("username and password cannot be empty")
        return
    # 从本地存储读取已存的用户数据
    users_str = localStorage.getItem("user_data")
    users = json.loads(users_str) if users_str else {}
    # 用户名重复校验
    if username in users:
        print("user already exists")
        return
    # 写入新用户数据
    users[username] = password
    localStorage.setItem("user_data", json.dumps(users))
    print("user created")

# 绑定注册按钮点击事件
Element("register-btn").element.addEventListener("click", danm)
</py-script>

注意:这个方案的数据存在当前浏览器的本地存储里,如果用户清理浏览器缓存会导致数据丢失,只适合个人本地小工具场景使用。

内容的提问来源于stack exchange,提问作者Dev-Adalz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 03:24:16