本文介紹了如何從電子前端進行數據庫調用?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
(這里是全新的學習電子,所以我相信這是一個基本的問題,我遺漏了一些基本的東西…)
如何從電子應用程序前端與本地數據庫(我使用的是Sqlite)交互?我有一個非常基本的數據庫管理器類,在我的Electron應用程序的index.js
文件中使用它沒有問題。但是從前端(我使用的是Svelte,但我可能可以翻譯來自其他前端框架的解決方案),如何與數據庫交互?這似乎很基本,但我正在努力尋找一個基本的例子。
既然所有東西都是本地的,似乎不應該僅僅為了來回封送數據而設置整個API,但也許它是必要的?但如果是這樣的話,人們該如何告訴電子后端(如果這是正確的說法)去做一些事情,并將結果返回給前端呢?我看到了一些關于IPC的東西,但現在沒有太大的意義,看起來有點矯枉過正。
以下是我的簡單數據庫管理器類:
const sqlite3 = require("sqlite3").verbose();
class DbManager {
#db;
open() {
this.#db = new sqlite3.Database("testing.db", sqlite3.OPEN_READWRITE);
}
close() {
this.#db.close();
}
run(sql, param) {
this.#db.run(sql, param);
return this;
}
}
const manager = new DbManager();
module.exports = manager;
我可以從電子入口點調用它并執行任何沒有問題的操作index.js
:
const { app, BrowserWindow, screen } = require("electron");
require("electron-reload")(__dirname);
const db = require("./src/repository/db");
const createWindow = () => {
...
};
let window = null;
app.whenReady().then(() => {
db.open();
createWindow();
});
app.on("window-all-closed", () => {
db.close();
app.quit();
});
但是如何處理我的組件?
<script>
// this won't work, and I wouldn't expect it to, but not sure what the alternative is
const db = require("./repository/db");
let accountName;
function addAccount() {
db.run("INSERT INTO accounts (name) VALUES ($name);", { $name: accountName });
}
</script>
<main>
<form>
<label for="account_name">Account name</label>
<input id="account_name" bind:value={accountName} />
<button on:click={addAccount}>Add account</button>
</form>
</main>
如果有人知道一個樣板實現可以做類似的事情,那將是非常有幫助的。顯然,這就像這里的應用程序101;我只是還不確定如何在Electron中進行這項工作,如果有人給我指路的話,我會很感激的。
推薦答案
如果您百分之百確定您的應用程序不會訪問任何遠程資源,則只需公開require
以及通過預加載腳本可能需要的任何其他內容,只需編寫const nodeRequire = require; window.require = nodeRequire;
。
這是一個相當廣泛的主題,需要一些閱讀。我將嘗試為您提供入門知識并鏈接一些資源。
電子在兩個(如果打開多個窗口)進程上運行-主進程和呈現器進程。主進程處理打開新窗口、啟動和關閉整個應用程序、任務欄圖標、窗口可見性等事務,而呈現器進程基本上就像瀏覽器中的JS代碼。More on Electron processes。
默認情況下,呈現器進程不能訪問Node運行時,但可以允許它訪問。您可以通過兩種方式做到這一點,但有許多注意事項。
一種方法是在創建BrowserWindow
(注:nodeIntegration
is deprecated and weird時設置webPreferences.nodeIntegration = true
。這允許您在前端代碼中使用所有NodeAPI,并且您的代碼片段可以工作。但您可能不應該這樣做,因為BrowserWindow
能夠加載外部URL,而這些頁面上包含的任何代碼都能夠在您或您用戶的計算機上執行任意代碼。
另一種方法是使用預加載腳本。預加載腳本在呈現器進程中運行,但可以訪問Node運行時和瀏覽器的window
對象(除非nodeIntegration
為真,否則Node全局變量將在實際的前端代碼運行之前從作用域中移除)。您只需設置window.require = require
,并在您的前端文件中使用Node代碼。但您可能也不應該這樣做,即使您非常小心要公開的內容,因為仍然很容易留下漏洞,并允許潛在攻擊者利用一些公開的API進入完全訪問權限,as demonstrated here。More on Electron security。
那么如何安全地做到這一點呢?將webPreferences.contextIsolation
設置為true
。這最終將預加載腳本上下文與呈現器上下文分開,而不是由nodeIntegration: false
導致的不可靠的Node API剝離,因此您幾乎可以確定沒有惡意代碼具有對Node的完全訪問權限。
然后您可以通過contextBridge.exposeInMainWorld
從預加載向前端公開特定的函數。例如:
contextBridge.exposeInMainWorld('Accounts', {
addAccount: async (accountData) => {
// validate & sanitize...
const success = await db.run('...');
return success;
}
}
這會安全地將window
中指定方法的Accounts
對象公開在前端。因此,您可以在組件中編寫:
const accountAdded = await Accounts.addAccount({id: 123, username: 'foo'});
請注意,您仍然可以公開runDbCommand(command) { db.run(command) }
甚至evalInNode(code) { eval(code) }
這樣的方法,這就是為什么我說幾乎是確定的。
您實際上不需要使用IPC來處理文件或數據庫之類的事情,因為這些API在預加載中可用。僅當您要從呈現器進程操作窗口或在主進程上觸發任何其他內容時,才需要IPC。
這篇關于如何從電子前端進行數據庫調用?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,