Skip to main content

protocol

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

进程:主进程

🌐 Process: Main

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

🌐 An example of implementing a protocol that has the same effect as the file:// protocol:

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

除非另有说明,所有方法只能在 app 模块发出 ready 事件之后使用。

protocol 与自定义的 partitionsession 一起使用

🌐 Using protocol with a custom partition or session

协议会注册到特定的 Electron session 对象。如果你不指定会话,那么你的 protocol 将应用到 Electron 使用的默认会话。然而,如果你在 browserWindowwebPreferences 上定义 partitionsession,那么该窗口将使用不同的会话,如果你只是使用 electron.protocol.XXX,你的自定义协议将无法工作。

🌐 A protocol is registered to a specific Electron session object. If you don't specify a session, then your protocol will be applied to the default session that Electron uses. However, if you define a partition or session on your browserWindow's webPreferences, then that window will use a different session and your custom protocol will not work if you just use electron.protocol.XXX.

要让你的自定义协议与自定义会话一起工作,你需要将其明确注册到该会话中。

🌐 To have your custom protocol work in combination with a custom session, you need to register it to that session explicitly.

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

方法

🌐 Methods

protocol 模块具有以下方法:

🌐 The protocol module has the following methods:

protocol.registerSchemesAsPrivileged(customSchemes)

note

该方法只能在 app 模块的 ready 事件触发之前使用,并且只能调用一次。

scheme 注册为标准、安全,绕过资源的内容安全策略,允许注册 ServiceWorker,支持 fetch API、流式视频/音频和 V8 代码缓存。指定值为 true 的特权以启用此功能。

🌐 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.

注册特权方案的示例,可绕过内容安全策略(CSP):

🌐 An example of registering a privileged scheme, that bypasses Content Security Policy:

const { protocol } = require('electron')

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

一个标准方案遵循 RFC 3986 所称的通用 URI 语法。 例如,httphttps 是标准方案,而 file 不是。

🌐 A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example http and https are standard schemes, while file is not.

将一个方案注册为标准方案可以在提供服务时正确解析相对和绝对资源。否则,该方案将表现得像 file 协议,但无法解析相对 URL。

🌐 Registering a scheme as standard allows relative and absolute resources to be resolved correctly when served. Otherwise the scheme will behave like the file protocol, but without the ability to resolve relative URLs.

例如,当你使用自定义协议加载以下页面而未将其注册为标准方案时,图片将无法加载,因为非标准方案无法识别相对URL:

🌐 For example when you load following page with custom protocol without registering it as standard scheme, the image will not be loaded because non-standard schemes can not recognize relative URLs:

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

将一个方案注册为标准方案将允许通过 文件系统 API 访问文件。否则,渲染器将对该方案抛出安全错误。

🌐 Registering a scheme as standard will allow access to files through the FileSystem API. Otherwise the renderer will throw a security error for the scheme.

默认情况下,Web 存储 API(localStorage、sessionStorage、webSQL、indexedDB、cookies)在非标准方案中是被禁用的。因此,一般来说,如果你想注册一个自定义协议来替代 http 协议,你必须将其注册为标准方案。

🌐 By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies) are disabled for non standard schemes. So in general if you want to register a custom protocol to replace the http protocol, you have to register it as a standard scheme.

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

🌐 Protocols that use streams (http and stream protocols) should set stream: true. The <video> and <audio> HTML elements expect protocols to buffer their responses by default. The stream flag configures those elements to correctly expect streaming responses.

protocol.handle(scheme, handler)

  • scheme 字符串——处理例如 httpsmy-app 的方案。这是 URL 中 : 之前的部分。
  • handler Function<GlobalResponse | Promise<GlobalResponse>>

scheme 注册一个协议处理程序。对使用此方案的 URL 发出的请求将委托给该处理程序来确定应发送的响应。

🌐 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.

可以返回 ResponsePromise<Response>

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

示例:

🌐 Example:

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 以获取更多详细信息。

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

protocol.unhandle(scheme)

  • scheme 字符串 - 要移除处理程序的方案。

移除已在 protocol.handle 注册的协议处理程序。

🌐 Removes a protocol handler registered with protocol.handle.

protocol.isProtocolHandled(scheme)

  • scheme 字符串

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

🌐 Returns boolean - Whether scheme is already handled.

protocol.registerFileProtocol(scheme, handler) 已弃用

🌐 protocol.registerFileProtocol(scheme, handler) Deprecated

History

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

🌐 Returns boolean - Whether the protocol was successfully registered

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

🌐 Registers a protocol of scheme that will send a file as the response. The handler will be called with request and callback where request is an incoming request for the scheme.

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

🌐 To handle the request, the callback should be called with either the file's path or an object that has a path property, e.g. callback(filePath) or callback({ path: filePath }). The filePath must be an absolute path.

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

🌐 By default the scheme is treated like http:, which is parsed differently from protocols that follow the "generic URI syntax" like file:.

protocol.registerBufferProtocol(scheme, handler) 已弃用

🌐 protocol.registerBufferProtocol(scheme, handler) Deprecated

History

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

🌐 Returns boolean - Whether the protocol was successfully registered

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

🌐 Registers a protocol of scheme that will send a Buffer as a response.

用法与 registerFileProtocol 相同,只是 callback 应该使用一个 Buffer 对象或一个具有 data 属性的对象来调用。

🌐 The usage is the same with registerFileProtocol, except that the callback should be called with either a Buffer object or an object that has the data property.

示例:

🌐 Example:

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

protocol.registerStringProtocol(scheme, handler) 已弃用

🌐 protocol.registerStringProtocol(scheme, handler) Deprecated

History

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

🌐 Returns boolean - Whether the protocol was successfully registered

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

🌐 Registers a protocol of scheme that will send a string as a response.

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

🌐 The usage is the same with registerFileProtocol, except that the callback should be called with either a string or an object that has the data property.

protocol.registerHttpProtocol(scheme, handler) 已弃用

🌐 protocol.registerHttpProtocol(scheme, handler) Deprecated

History

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

🌐 Returns boolean - Whether the protocol was successfully registered

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

🌐 Registers a protocol of scheme that will send an HTTP request as a response.

用法与 registerFileProtocol 相同,不同之处在于 callback 应该用一个具有 url 属性的对象来调用。

🌐 The usage is the same with registerFileProtocol, except that the callback should be called with an object that has the url property.

protocol.registerStreamProtocol(scheme, handler) 已弃用

🌐 protocol.registerStreamProtocol(scheme, handler) Deprecated

History

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

🌐 Returns boolean - Whether the protocol was successfully registered

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

🌐 Registers a protocol of scheme that will send a stream as a response.

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

🌐 The usage is the same with registerFileProtocol, except that the callback should be called with either a ReadableStream object or an object that has the data property.

示例:

🌐 Example:

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 事件)的对象。例如,下面是返回一个文件的方式:

🌐 It is possible to pass any object that implements the readable stream API (emits data/end/error events). For example, here's how a file could be returned:

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

protocol.unregisterProtocol(scheme) 已弃用

🌐 protocol.unregisterProtocol(scheme) Deprecated

History
  • scheme 字符串

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

🌐 Returns boolean - Whether the protocol was successfully unregistered

取消注册 scheme 的自定义协议。

🌐 Unregisters the custom protocol of scheme.

protocol.isProtocolRegistered(scheme) 已弃用

🌐 protocol.isProtocolRegistered(scheme) Deprecated

History
  • scheme 字符串

返回 boolean - scheme 是否已注册。

🌐 Returns boolean - Whether scheme is already registered.

protocol.interceptFileProtocol(scheme, handler) 已弃用

🌐 protocol.interceptFileProtocol(scheme, handler) Deprecated

History

返回 boolean - 协议是否被成功拦截

🌐 Returns boolean - Whether the protocol was successfully intercepted

拦截 scheme 协议,并使用 handler 作为该协议的新处理器,发送文件作为响应。

🌐 Intercepts scheme protocol and uses handler as the protocol's new handler which sends a file as a response.

protocol.interceptStringProtocol(scheme, handler) 已弃用

🌐 protocol.interceptStringProtocol(scheme, handler) Deprecated

History

返回 boolean - 协议是否被成功拦截

🌐 Returns boolean - Whether the protocol was successfully intercepted

拦截 scheme 协议并使用 handler 作为该协议的新处理程序,它会发送 string 作为响应。

🌐 Intercepts scheme protocol and uses handler as the protocol's new handler which sends a string as a response.

protocol.interceptBufferProtocol(scheme, handler) 已弃用

🌐 protocol.interceptBufferProtocol(scheme, handler) Deprecated

History

返回 boolean - 协议是否被成功拦截

🌐 Returns boolean - Whether the protocol was successfully intercepted

拦截 scheme 协议,并使用 handler 作为该协议的新处理程序,它会发送 Buffer 作为响应。

🌐 Intercepts scheme protocol and uses handler as the protocol's new handler which sends a Buffer as a response.

protocol.interceptHttpProtocol(scheme, handler) 已弃用

🌐 protocol.interceptHttpProtocol(scheme, handler) Deprecated

History

返回 boolean - 协议是否被成功拦截

🌐 Returns boolean - Whether the protocol was successfully intercepted

拦截 scheme 协议并使用 handler 作为协议的新处理器,该处理器发送一个新的 HTTP 请求作为响应。

🌐 Intercepts scheme protocol and uses handler as the protocol's new handler which sends a new HTTP request as a response.

protocol.interceptStreamProtocol(scheme, handler) 已弃用

🌐 protocol.interceptStreamProtocol(scheme, handler) Deprecated

History

返回 boolean - 协议是否被成功拦截

🌐 Returns boolean - Whether the protocol was successfully intercepted

protocol.registerStreamProtocol 相同,只是它会替换现有的协议处理程序。

🌐 Same as protocol.registerStreamProtocol, except that it replaces an existing protocol handler.

protocol.uninterceptProtocol(scheme) 已弃用

🌐 protocol.uninterceptProtocol(scheme) Deprecated

History
  • scheme 字符串

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

🌐 Returns boolean - Whether the protocol was successfully unintercepted

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

🌐 Remove the interceptor installed for scheme and restore its original handler.

protocol.isProtocolIntercepted(scheme) 已弃用

🌐 protocol.isProtocolIntercepted(scheme) Deprecated

History
  • scheme 字符串

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

🌐 Returns boolean - Whether scheme is already intercepted.