跳转到主内容

protocol

注册自定义协议并拦截基于现有协议的请求。

进程:主进程

实现与 file:// 协议具有相同效果的协议的示例:

const { app, protocol, net } = require('electron')

app.whenReady().then(() => {
protocol.handle('atom', (request) =>
net.fetch('file://' + request.url.slice('atom://'.length)))
})

注意: 除了指定的方法, 其他方法只能在 app 模块的 ready 事件被触发后使用。

用自定义的 partitionsession 来使用 protocol

一个 protocol 是注册到特定 Electron 的 session 对象。 如果你不指定一个 session,那 protocol 将使用 Electron 默认提供的 session 。 然而, 如果你定义了 partition 或者 session 在你的 browserWindowwebPreferences, 对应 window 将使用不同的 session 。同时如果你使用 electron.protocol.XXX ,则自定义的 protocol 将不会工作

要使自定义协议与自定义会话相结合,你需要明确注册该会话。

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.join(__dirname, filePath)).toString())
})

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

方法

protocol 模块具有以下方法:

protocol.registerSchemesAsPrivileged(customSchemes)

注意. 此方法只能在 appready 事件触发前调用,且只能调用一次

Registers the scheme as standard, secure, bypasses content security policy for resources, allows registering ServiceWorker, supports fetch API, streaming video/audio, and V8 code cache. Specify a privilege with the value of true to enable the capability.

下面是一个注册特权协议的示例代码,可以绕过内容安全策略:

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

标准scheme遵循 RFC 3986 所设定的 URI泛型语法 。 例如, httphttps 是标准协议, 而 file 不是。

按标准将一个scheme注册, 将保证相对和绝对资源在使用时能够得到正确的解析。 否则, 该协议将表现为 file 协议, 而且,这种文件协议将不能解析相对路径。

例如, 当您使用自定义协议加载以下内容时,如果你不将其注册为标准scheme, 图片将不会被加载, 因为非标准scheme无法识别相对 路径:

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

注册一个scheme作为标准scheme将允许其通过FileSystem 接口访问文件。 否则, 渲染器将会因为该scheme,而抛出一个安全性错误。

在非标准 schemes 下,网络存储 Api (localStorage, sessionStorage, webSQL, indexedDB, cookies) 默认是被禁用的。 所以一般来说如果你想注册一个自定义协议来替换http协议,你必须将其注册为标准 scheme:

如果 Protocols 需要使用流 (http 和 stream 协议) 应设置 stream: true<video><audio> HTML 元素默认需要协议缓冲其响应内容。 stream 标志将这些元素配置为正确的流媒体响应

protocol.handle(scheme, handler)

  • scheme string - scheme to handle, for example https or my-app. This is the bit before the : in a URL.
  • handler Function<GlobalResponse | Promise<GlobalResponse\>\>

Register a protocol handler for scheme. Requests made to URLs with this scheme will delegate to this handler to determine what response should be sent.

Either a Response or a Promise<Response> can be returned.

示例:

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
})
}
})
})

See the MDN docs for Request and Response for more details.

protocol.unhandle(scheme)

  • scheme string - scheme for which to remove the handler.

Removes a protocol handler registered with protocol.handle.

protocol.isProtocolHandled(scheme)

  • scheme string

Returns boolean - Whether scheme is already handled.

protocol.registerFileProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否注册成功

注册一个 scheme 协议, 并将该文件作为响应返回。 当 requestscheme 内需要的请求时,requestcallback 将自动调用 handler

要处理 request, 应当使用文件的路径或具有 path 属性的对象来调用 callback。例如:callback(filePath)callback({ path: filePath }). filePath 必须是绝对路径

默认情况下, scheme 被当作 http:对待,与遵循"通用URI语法"的协议(如 file:)有不同的解析过程。

protocol.registerBufferProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否注册成功

注册一个 scheme 协议, 将 Buffer作为响应发送

用法类似于 registerFileProtocol ,只是callback 会被Buffer对象或者带有data属性的对象调用。

示例:

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

protocol.registerStringProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否注册成功

注册一个 scheme 协议, 将 string 作为响应发送

除了 callback 只能被string 或拥有 data 属性的对象调用,使用方法与registerFileProtocol 相同

protocol.registerHttpProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否注册成功

注册一个 scheme 协议, 将 HTTP 请求作为响应发送

除了 callback 只能被拥有 url 属性的对象调用外,使用方法与 registerFileProtocol相同。

protocol.registerStreamProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否注册成功

注册一个 scheme 的协议将发送一个流作为响应。

除了 callback 方法只能被 ReadableStream 对象或拥有 data 属性的对象调用外,使用方法与 registerFileProtocol 相同。

示例:

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 string

Returns boolean - 协议是否成功取消注册

取消对自定义scheme的注册

protocol.isProtocolRegistered(scheme) 已废弃

  • scheme string

Returns boolean - 当前 scheme 是否已注册

protocol.interceptFileProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否被拦截成功

终止 scheme 协议, 并将 handler 作为该protocol新的处理方式,即返回一个file。

protocol.interceptStringProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否被拦截成功

终止 scheme 协议, 并将 handler 作为该protocol新的处理方式,即返回一个string

protocol.interceptBufferProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否被拦截成功

终止 scheme 协议, 并将 handler 作为该protocol新的处理方式,即返回一个Buffer

protocol.interceptHttpProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否被拦截成功

终止 scheme 协议, 并将 handler 作为该protocol新的处理方式,即返回一个新 HTTP 请求。

protocol.interceptStreamProtocol(scheme, handler) 已废弃

Returns boolean - 当前协议是否被拦截成功

它与 registerStreamProtocol方法相同, 不过它是用来替换现有的protocol处理方式。

protocol.uninterceptProtocol(scheme) 已废弃

  • scheme string

Returns boolean - 当前协议是否已成功解除拦截

移除为 scheme 安装的拦截器,并还原其原始处理方式。

protocol.isProtocolIntercepted(scheme) 已废弃

  • scheme string

Returns boolean - 表示是否已拦截了 scheme