跳转到主要内容

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('node: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 的特权来启用该功能。

注册一个特权 scheme,绕过内容安全策略的示例

const { protocol } = require('electron')

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

标准 scheme 符合 RFC 3986 中所说的 通用 URI 语法。例如,httphttps 是标准 scheme,而 file 则不是。

将 scheme 注册为标准 scheme,可以正确解析相对和绝对资源。否则,该 scheme 的行为将类似于 file 协议,但无法解析相对 URL。

例如,当您使用自定义协议加载以下页面而不将其注册为标准 scheme 时,图像将无法加载,因为非标准 scheme 无法识别相对 URL。

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

将 scheme 注册为标准 scheme,将允许通过 FileSystem API 访问文件。否则,渲染器将为此 scheme 引发安全错误。

默认情况下,Web 存储 API(localStorage、sessionStorage、webSQL、indexedDB、cookies)对非标准 scheme 是禁用的。所以通常情况下,如果您想注册一个自定义协议来替换 http 协议,您必须将其注册为标准 scheme。

使用流的协议(http 和 stream 协议)应设置 stream: true<video><audio> HTML 元素默认期望协议缓冲其响应。stream 标志会配置这些元素,使其正确期望流式响应。

protocol.handle(scheme, handler)

  • scheme string - 要处理的 scheme,例如 httpsmy-app。这是 URL 中 : 前面的部分。
  • handler Function<GlobalResponse | Promise<GlobalResponse>>

scheme 注册协议处理程序。对具有此 scheme 的 URL 的请求将委托给此处理程序来确定应发送什么响应。

可以返回 ResponsePromise<Response>

示例

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

const path = require('node:path')
const { pathToFileURL } = require('node: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 string - 要移除处理程序的 scheme。

删除使用 protocol.handle 注册的协议处理程序。

protocol.isProtocolHandled(scheme)

  • scheme string

返回 boolean - scheme 是否已被处理。

protocol.registerFileProtocol(scheme, handler) 已弃用

历史

返回 boolean - 协议是否注册成功

注册一个 scheme 协议,该协议将发送一个文件作为响应。handler 将使用 requestcallback 进行调用,其中 request 是对 scheme 的传入请求。

为了处理 requestcallback 应该使用文件的路径或具有 path 属性的对象进行调用,例如 callback(filePath)callback({ path: filePath })filePath 必须是绝对路径。

默认情况下,scheme 被视为 http:,其解析方式与遵循“通用 URI 语法”的协议(如 file:)不同。

protocol.registerBufferProtocol(scheme, handler) 已弃用

历史

返回 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) 已弃用

历史

返回 boolean - 协议是否注册成功

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

用法与 registerFileProtocol 相同,只是 callback 应该使用 string 或具有 data 属性的对象进行调用。

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('node: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

返回 boolean - 协议是否成功注销

注销 scheme 的自定义协议。

protocol.isProtocolRegistered(scheme) 已弃用

历史
  • scheme string

返回 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 string

返回 boolean - 协议是否已成功取消拦截

删除为 scheme 安装的拦截器并恢复其原始处理程序。

protocol.isProtocolIntercepted(scheme) 已弃用

历史
  • scheme string

返回 boolean - scheme 是否已被拦截。