跳到主要內容

protocol

註冊自訂協定並攔截現有協定請求。

程序:主要

實作與 file:// 協定具有相同效果的協定範例

const { app, protocol, net } = require('electron')
const path = require('node:path')
const url = require('node:url')

app.whenReady().then(() => {
protocol.handle('atom', (request) => {
const filePath = request.url.slice('atom://'.length)
return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString())
})
})

注意:除非另有說明,所有方法只能在 app 模組發出 ready 事件後使用。

protocol 與自訂 partitionsession 搭配使用

協定會註冊到特定的 Electron session 物件。如果您沒有指定 session,則您的 protocol 將會套用到 Electron 使用的預設 session。但是,如果您在 browserWindowwebPreferences 上定義 partitionsession,則該視窗將會使用不同的 session,而且如果您只使用 electron.protocol.XXX,則您的自訂協定將不會運作。

若要讓您的自訂協定與自訂 session 搭配運作,您需要將其明確註冊到該 session。

const { app, BrowserWindow, net, protocol, session } = require('electron')
const path = require('node:path')
const url = require('url')

app.whenReady().then(() => {
const partition = 'persist:example'
const ses = session.fromPartition(partition)

ses.protocol.handle('atom', (request) => {
const filePath = request.url.slice('atom://'.length)
return net.fetch(url.pathToFileURL(path.resolve(__dirname, filePath)).toString())
})

const mainWindow = new BrowserWindow({ webPreferences: { partition } })
})

方法

protocol 模組具有下列方法

protocol.registerSchemesAsPrivileged(customSchemes)

注意:此方法只能在 app 模組發出 ready 事件之前使用,而且只能呼叫一次。

scheme 註冊為標準、安全,繞過資源的內容安全策略,允許註冊 ServiceWorker,支援 fetch API、串流視訊/音訊和 V8 程式碼快取。使用 true 值指定權限以啟用功能。

註冊繞過內容安全策略的特權協定範例

const { protocol } = require('electron')
protocol.registerSchemesAsPrivileged([
{ scheme: 'foo', privileges: { bypassCSP: true } }
])

標準協定會遵循 RFC 3986 所謂的通用 URI 語法。例如,httphttps 是標準協定,而 file 則不是。

將協定註冊為標準可讓相對和絕對資源在服務時正確解析。否則,協定會像 file 協定一樣運作,但無法解析相對 URL。

例如,當您使用自訂協定載入下列頁面而不將其註冊為標準協定時,影像將不會載入,因為非標準協定無法識別相對 URL

<body>
<img src='test.png'>
</body>

將協定註冊為標準將允許透過 FileSystem API 存取檔案。否則,渲染器會針對協定擲回安全性錯誤。

根據預設,非標準協定會停用 Web 儲存 API(localStorage、sessionStorage、webSQL、indexedDB、cookie)。因此,一般而言,如果您想要註冊自訂協定以取代 http 協定,您必須將其註冊為標準協定。

使用串流的協定(http 和串流協定)應設定 stream: true<video><audio> HTML 元素預期協定預設會緩衝其回應。stream 旗標會設定這些元素以正確預期串流回應。

protocol.handle(scheme, handler)

  • scheme 字串 - 要處理的協定,例如 httpsmy-app。這是 URL 中 : 之前的部分。
  • handler Function<GlobalResponse | Promise<GlobalResponse>>

註冊 scheme 的協定處理常式。使用此協定對 URL 發出的請求會委派給此處理常式,以判斷應該傳送什麼回應。

可以傳回 ResponsePromise<Response>

範例

const { app, net, protocol } = require('electron')
const path = require('node:path')
const { pathToFileURL } = require('url')

protocol.registerSchemesAsPrivileged([
{
scheme: 'app',
privileges: {
standard: true,
secure: true,
supportFetchAPI: true
}
}
])

app.whenReady().then(() => {
protocol.handle('app', (req) => {
const { host, pathname } = new URL(req.url)
if (host === 'bundle') {
if (pathname === '/') {
return new Response('<h1>hello, world</h1>', {
headers: { 'content-type': 'text/html' }
})
}
// NB, this checks for paths that escape the bundle, e.g.
// app://bundle/../../secret_file.txt
const pathToServe = path.resolve(__dirname, pathname)
const relativePath = path.relative(__dirname, pathToServe)
const isSafe = relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
if (!isSafe) {
return new Response('bad', {
status: 400,
headers: { 'content-type': 'text/html' }
})
}

return net.fetch(pathToFileURL(pathToServe).toString())
} else if (host === 'api') {
return net.fetch('https://api.my-server.com/' + pathname, {
method: req.method,
headers: req.headers,
body: req.body
})
}
})
})

請參閱 MDN 文件以取得 RequestResponse 的詳細資訊。

protocol.unhandle(scheme)

  • scheme 字串 - 要移除處理常式的協定。

移除使用 protocol.handle 註冊的協定處理常式。

protocol.isProtocolHandled(scheme)

  • scheme 字串

傳回 boolean - 是否已處理 scheme

protocol.registerFileProtocol(scheme, handler) 已棄用

歷史

傳回 boolean - 協定是否已成功註冊

註冊 scheme 的協定,該協定會將檔案做為回應傳送。將會使用 requestcallback 呼叫 handler,其中 requestscheme 的傳入請求。

若要處理 request,應該使用檔案的路徑或具有 path 屬性的物件呼叫 callback,例如 callback(filePath)callback({ path: filePath })filePath 必須是絕對路徑。

根據預設,scheme 的處理方式類似 http:,這與遵循「通用 URI 語法」的協定(例如 file:)不同。

protocol.registerBufferProtocol(scheme, handler) 已棄用

歷史

傳回 boolean - 協定是否已成功註冊

註冊 scheme 的協定,該協定會傳送 Buffer 做為回應。

用法與 registerFileProtocol 相同,只是應該使用 Buffer 物件或具有 data 屬性的物件呼叫 callback

範例

protocol.registerBufferProtocol('atom', (request, callback) => {
callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') })
})

protocol.registerStringProtocol(scheme, handler) 已棄用

歷史

傳回 boolean - 協定是否已成功註冊

註冊 scheme 的協定,該協定會傳送 string 做為回應。

用法與 registerFileProtocol 相同,只是應該使用 string 或具有 data 屬性的物件呼叫 callback

protocol.registerHttpProtocol(scheme, handler) 已棄用

歷史

傳回 boolean - 協定是否已成功註冊

註冊一個 scheme 的協定,該協定會發送 HTTP 請求作為回應。

用法與 registerFileProtocol 相同,差別在於 callback 應使用具有 url 屬性的物件來呼叫。

protocol.registerStreamProtocol(scheme, handler) 已棄用

歷史

傳回 boolean - 協定是否已成功註冊

註冊一個 scheme 的協定,該協定會發送串流作為回應。

用法與 registerFileProtocol 相同,差別在於 callback 應使用 ReadableStream 物件或具有 data 屬性的物件來呼叫。

範例

const { protocol } = require('electron')
const { PassThrough } = require('stream')

function createStream (text) {
const rv = new PassThrough() // PassThrough is also a Readable stream
rv.push(text)
rv.push(null)
return rv
}

protocol.registerStreamProtocol('atom', (request, callback) => {
callback({
statusCode: 200,
headers: {
'content-type': 'text/html'
},
data: createStream('<h5>Response</h5>')
})
})

可以傳遞任何實作可讀串流 API 的物件(發射 data/end/error 事件)。例如,以下是如何返回檔案的方式

protocol.registerStreamProtocol('atom', (request, callback) => {
callback(fs.createReadStream('index.html'))
})

protocol.unregisterProtocol(scheme) 已棄用

歷史
  • scheme 字串

回傳 boolean - 是否成功取消註冊協定

取消註冊 scheme 的自訂協定。

protocol.isProtocolRegistered(scheme) 已棄用

歷史
  • scheme 字串

回傳 boolean - scheme 是否已註冊。

protocol.interceptFileProtocol(scheme, handler) 已棄用

歷史

回傳 boolean - 是否成功攔截協定

攔截 scheme 協定,並使用 handler 作為協定的新處理程式,以檔案作為回應。

protocol.interceptStringProtocol(scheme, handler) 已棄用

歷史

回傳 boolean - 是否成功攔截協定

攔截 scheme 協定,並使用 handler 作為協定的新處理程式,以 string 作為回應。

protocol.interceptBufferProtocol(scheme, handler) 已棄用

歷史

回傳 boolean - 是否成功攔截協定

攔截 scheme 協定,並使用 handler 作為協定的新處理程式,以 Buffer 作為回應。

protocol.interceptHttpProtocol(scheme, handler) 已棄用

歷史

回傳 boolean - 是否成功攔截協定

攔截 scheme 協定,並使用 handler 作為協定的新處理程式,以新的 HTTP 請求作為回應。

protocol.interceptStreamProtocol(scheme, handler) 已棄用

歷史

回傳 boolean - 是否成功攔截協定

protocol.registerStreamProtocol 相同,差別在於它會取代現有的協定處理程式。

protocol.uninterceptProtocol(scheme) 已棄用

歷史
  • scheme 字串

回傳 boolean - 是否成功取消攔截協定

移除為 scheme 安裝的攔截器,並還原其原始處理程式。

protocol.isProtocolIntercepted(scheme) 已棄用

歷史
  • scheme 字串

回傳 boolean - scheme 是否已攔截。