本文介紹了如何從電子前端進(jìn)行數(shù)據(jù)庫(kù)調(diào)用?的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!
問(wèn)題描述
(這里是全新的學(xué)習(xí)電子,所以我相信這是一個(gè)基本的問(wèn)題,我遺漏了一些基本的東西…)
如何從電子應(yīng)用程序前端與本地?cái)?shù)據(jù)庫(kù)(我使用的是Sqlite)交互?我有一個(gè)非常基本的數(shù)據(jù)庫(kù)管理器類,在我的Electron應(yīng)用程序的index.js文件中使用它沒有問(wèn)題。但是從前端(我使用的是Svelte,但我可能可以翻譯來(lái)自其他前端框架的解決方案),如何與數(shù)據(jù)庫(kù)交互?這似乎很基本,但我正在努力尋找一個(gè)基本的例子。
既然所有東西都是本地的,似乎不應(yīng)該僅僅為了來(lái)回封送數(shù)據(jù)而設(shè)置整個(gè)API,但也許它是必要的?但如果是這樣的話,人們?cè)撊绾胃嬖V電子后端(如果這是正確的說(shuō)法)去做一些事情,并將結(jié)果返回給前端呢?我看到了一些關(guān)于IPC的東西,但現(xiàn)在沒有太大的意義,看起來(lái)有點(diǎn)矯枉過(guò)正。
以下是我的簡(jiǎn)單數(shù)據(jù)庫(kù)管理器類:
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;
我可以從電子入口點(diǎn)調(diào)用它并執(zhí)行任何沒有問(wèn)題的操作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>
如果有人知道一個(gè)樣板實(shí)現(xiàn)可以做類似的事情,那將是非常有幫助的。顯然,這就像這里的應(yīng)用程序101;我只是還不確定如何在Electron中進(jìn)行這項(xiàng)工作,如果有人給我指路的話,我會(huì)很感激的。
推薦答案
如果您百分之百確定您的應(yīng)用程序不會(huì)訪問(wèn)任何遠(yuǎn)程資源,則只需公開require以及通過(guò)預(yù)加載腳本可能需要的任何其他內(nèi)容,只需編寫const nodeRequire = require; window.require = nodeRequire;。
這是一個(gè)相當(dāng)廣泛的主題,需要一些閱讀。我將嘗試為您提供入門知識(shí)并鏈接一些資源。
電子在兩個(gè)(如果打開多個(gè)窗口)進(jìn)程上運(yùn)行-主進(jìn)程和呈現(xiàn)器進(jìn)程。主進(jìn)程處理打開新窗口、啟動(dòng)和關(guān)閉整個(gè)應(yīng)用程序、任務(wù)欄圖標(biāo)、窗口可見性等事務(wù),而呈現(xiàn)器進(jìn)程基本上就像瀏覽器中的JS代碼。More on Electron processes。
默認(rèn)情況下,呈現(xiàn)器進(jìn)程不能訪問(wèn)Node運(yùn)行時(shí),但可以允許它訪問(wèn)。您可以通過(guò)兩種方式做到這一點(diǎn),但有許多注意事項(xiàng)。
一種方法是在創(chuàng)建BrowserWindow(注:nodeIntegrationis deprecated and weird時(shí)設(shè)置webPreferences.nodeIntegration = true。這允許您在前端代碼中使用所有NodeAPI,并且您的代碼片段可以工作。但您可能不應(yīng)該這樣做,因?yàn)?code>BrowserWindow能夠加載外部URL,而這些頁(yè)面上包含的任何代碼都能夠在您或您用戶的計(jì)算機(jī)上執(zhí)行任意代碼。
另一種方法是使用預(yù)加載腳本。預(yù)加載腳本在呈現(xiàn)器進(jìn)程中運(yùn)行,但可以訪問(wèn)Node運(yùn)行時(shí)和瀏覽器的window對(duì)象(除非nodeIntegration為真,否則Node全局變量將在實(shí)際的前端代碼運(yùn)行之前從作用域中移除)。您只需設(shè)置window.require = require,并在您的前端文件中使用Node代碼。但您可能也不應(yīng)該這樣做,即使您非常小心要公開的內(nèi)容,因?yàn)槿匀缓苋菀琢粝侣┒矗⒃试S潛在攻擊者利用一些公開的API進(jìn)入完全訪問(wèn)權(quán)限,as demonstrated here。More on Electron security。
那么如何安全地做到這一點(diǎn)呢?將webPreferences.contextIsolation設(shè)置為true。這最終將預(yù)加載腳本上下文與呈現(xiàn)器上下文分開,而不是由nodeIntegration: false導(dǎo)致的不可靠的Node API剝離,因此您幾乎可以確定沒有惡意代碼具有對(duì)Node的完全訪問(wèn)權(quán)限。
然后您可以通過(guò)contextBridge.exposeInMainWorld從預(yù)加載向前端公開特定的函數(shù)。例如:
contextBridge.exposeInMainWorld('Accounts', {
addAccount: async (accountData) => {
// validate & sanitize...
const success = await db.run('...');
return success;
}
}
這會(huì)安全地將window中指定方法的Accounts對(duì)象公開在前端。因此,您可以在組件中編寫:
const accountAdded = await Accounts.addAccount({id: 123, username: 'foo'});
請(qǐng)注意,您仍然可以公開runDbCommand(command) { db.run(command) }甚至evalInNode(code) { eval(code) }這樣的方法,這就是為什么我說(shuō)幾乎是確定的。
您實(shí)際上不需要使用IPC來(lái)處理文件或數(shù)據(jù)庫(kù)之類的事情,因?yàn)檫@些API在預(yù)加載中可用。僅當(dāng)您要從呈現(xiàn)器進(jìn)程操作窗口或在主進(jìn)程上觸發(fā)任何其他內(nèi)容時(shí),才需要IPC。
這篇關(guān)于如何從電子前端進(jìn)行數(shù)據(jù)庫(kù)調(diào)用?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,






