Python 现代开发学习笔记

(十四)在页面脚本里读取 JSON

1. 浏览器中的异步请求

页面按钮需要在当前页面内读取或修改数据,可以用浏览器的 fetch。下面代码放在 app.js 中,由浏览器执行,异步写法与第八章 Python 中的 await 分别属于各自运行环境。

// 项目文件:web_project/src/webbook/static/app.js
// fetch交回响应,先看状态再读JSON;响应内容放入textContent,不作为HTML执行。
const output = document.querySelector("#api-output");
const statusLine = document.querySelector("#api-status");
const csrf = document.querySelector('meta[name="csrf-token"]').content;

async function requestJSON(url, options = {}) {
    const response = await fetch(url, {credentials: "same-origin", ...options});
    const value = await response.json();
    statusLine.textContent = `${options.method || "GET"} ${url} → ${response.status}`;
    output.textContent = JSON.stringify(value, null, 2);
    if (!response.ok)
        throw new Error(value.error || "请求未完成");
    return value;
}

const 声明这里不再重新绑定的名称;document.querySelector 按 CSS 选择器取得元素。meta 的 content 是令牌文本,后面用于写入请求头。

async function 声明异步函数。fetch 交回一个 Promise,await 等待响应;response.json() 再异步读取并解析正文。response.ok 检查状态是否在 200–299,网络成功返回一个 422 或 500 时,fetch 仍会交出响应对象,需要我们继续看状态。

{credentials:"same-origin",...options} 用 options 展开并覆盖默认配置,类似 Python 中合并字典。反引号字符串中的 ${表达式} 用于插入值;JSON.stringify 把数据变成便于阅读的文本。textContent 设置纯文本内容,页面不会把 API 返回的书名继续当作 HTML 解析。

2. 点击事件调用请求函数

这里 credentials 的 same-origin 对同源请求携带凭据,throw 抛出浏览器中的异常,catch 接住它;!response.ok 中的感叹号表示逻辑取反。

// 续写同一文件:web_project/src/webbook/static/app.js
document.querySelector("#load-api").addEventListener("click", async () => {
    try {
        await requestJSON("/api/books");
    } catch (error) {
        statusLine.textContent = error.message;
    }
});

addEventListener 注册点击回调,async () => {...} 是这里的异步箭头函数。用户点击后才发送请求,try/catch 显示错误,不会因为页面加载就反复读取。

// 续写同一文件:web_project/src/webbook/static/app.js
for (const button of document.querySelectorAll(".finish")) {
    button.addEventListener("click", async () => {
        button.disabled = true;
        try {
            await requestJSON(`/api/books/${button.dataset.id}/finish`, {
                method: "POST", headers: {"X-CSRF-Token": csrf}
            });
            location.reload();
        } catch (error) {
            statusLine.textContent = error.message;
            button.disabled = false;
        }
    });
}

querySelectorAll 取得所有待标记按钮。for...of 逐个注册事件,dataset.id 读取 HTML 中的 data-id;按下时先禁用按钮,发出 POST 并带上令牌,成功后 reload 重新取得服务器页面。失败时显示原因并恢复按钮。

点击触发fetch并等待响应,先核对状态再解析数据,读操作写入文本,写操作完成后重新取得页面

笔记正文与全部题解 · Ctrl / ⌘ K