PyScript open()写入本地JSON文件 刷新后数据丢失问题
核心原因
写入不持久是PyScript的运行机制+浏览器安全限制共同导致的,和你写的用户名重复校验逻辑无关:
- PyScript基于Pyodide运行在浏览器端独立沙箱中,所有通过
<py-env>预加载的文件,页面初始化时都会被复制到内存级虚拟文件系统。你代码里调用open()、json.load()、json.dump()操作的全程都是这份内存里的临时副本,根本没有触碰到磁盘上存储的实体login.json。 - 现代浏览器有强制安全规则:禁止网页脚本静默读写用户本地磁盘、服务器磁盘上的实体文件。页面刷新或关闭后沙箱内存会被直接回收,所有临时写入的数据自然全部清空。
- 不存在任何前端侧直接静默写本地实体文件的偏方,所有现代浏览器都封堵了相关能力,不用浪费时间尝试绕限。
实现方案
根据你的使用场景二选一即可,都能实现持久化存储不丢数据。
方案1:部署到Web服务器场景(推荐,符合站点使用逻辑)
不要尝试在前端PyScript代码里直接写服务器上的实体文件,加一层极简的后端接口处理文件读写即可,不需要复杂框架。
- 先写极简后端接口(以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"}
- 修改你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
相关产品推荐
相关产品推荐

