Skip to main content

프로토콜

커스텀 프로토콜을 등록하고 기존 프로토콜 요청을 가로챈다.

프로세스: 메인

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 이벤트가 발생하기 전에는 모든 메서드를 사용할 수 없다. 단, 특별히 명시된 경우는 예외이다.

커스텀 partition 또는 session과 함께 protocol 사용하기

프로토콜은 특정 Electron session 객체에 등록된다. 세션을 지정하지 않으면, 프로토콜은 Electron이 사용하는 기본 세션에 적용된다. 그러나 browserWindowwebPreferencespartition 또는 session을 정의하면, 해당 윈도우는 다른 세션을 사용하게 되고, 단순히 electron.protocol.XXX를 사용할 경우 커스텀 프로토콜이 동작하지 않는다.

커스텀 세션과 함께 커스텀 프로토콜을 사용하려면, 해당 세션에 명시적으로 프로토콜을 등록해야 한다.

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을 표준으로 등록하고, 보안을 적용하며, 리소스에 대한 콘텐츠 보안 정책(CSP)을 우회하고, ServiceWorker 등록을 허용하며, fetch API, 스트리밍 비디오/오디오, 그리고 V8 코드 캐시를 지원한다. 특정 기능을 활성화하려면 true 값을 가진 권한을 지정한다.

콘텐츠 보안 정책(CSP)을 우회하는 권한이 있는 scheme을 등록하는 예시:

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

표준 scheme은 RFC 3986에서 정의한 일반 URI 구문을 준수한다. 예를 들어 httphttps는 표준 scheme이지만, file은 그렇지 않다.

scheme을 표준으로 등록하면 서비스될 때 상대 및 절대 리소스가 올바르게 해석된다. 그렇지 않으면 scheme은 file 프로토콜과 유사하게 동작하지만, 상대 URL을 해석할 수 없다.

예를 들어, 표준 scheme으로 등록하지 않은 커스텀 프로토콜로 다음 페이지를 로드하면, 이미지가 로드되지 않는다. 비표준 scheme은 상대 URL을 인식할 수 없기 때문이다:

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

scheme을 표준으로 등록하면 FileSystem API를 통해 파일에 접근할 수 있다. 그렇지 않으면 렌더러는 해당 scheme에 대해 보안 오류를 발생시킨다.

기본적으로 비표준 scheme에 대해 웹 스토리지 API(localStorage, sessionStorage, webSQL, indexedDB, 쿠키)가 비활성화된다. 따라서 일반적으로 http 프로토콜을 대체할 커스텀 프로토콜을 등록하려면 표준 scheme으로 등록해야 한다.

스트림을 사용하는 프로토콜(http 및 스트림 프로토콜)은 stream: true를 설정해야 한다. <video><audio> HTML 엘리먼트는 기본적으로 프로토콜이 응답을 버퍼링할 것을 기대한다. stream 플래그는 이러한 엘리먼트가 스트리밍 응답을 올바르게 처리하도록 설정한다.

protocol.handle(scheme, handler)

  • scheme string - 처리할 스키마. 예를 들어 httpsmy-app과 같은 값이다. 이는 URL에서 : 앞에 오는 부분을 의미한다.
  • handler Function<GlobalResponse | Promise<GlobalResponse>>

scheme에 대한 프로토콜 핸들러를 등록한다. 이 스키마를 사용하는 URL로 요청이 들어오면, 이 핸들러가 어떤 응답을 보낼지 결정한다.

Response 또는 Promise<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, 이 부분은 번들 외부로 이탈하는 경로를 확인한다. 예를 들어
// 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
})
}
})
})

더 자세한 내용은 RequestResponse에 대한 MDN 문서를 참고한다.

protocol.unhandle(scheme)

  • scheme string - 핸들러를 제거할 scheme

protocol.handle로 등록된 프로토콜 핸들러를 제거한다.

protocol.isProtocolHandled(scheme)

  • scheme string

boolean을 반환한다. 해당 scheme이 이미 처리되었는지 여부를 나타낸다.

protocol.registerFileProtocol(scheme, handler) Deprecated

History

boolean을 반환한다 - 프로토콜이 성공적으로 등록되었는지 여부를 나타낸다.

scheme 프로토콜을 등록하여 파일을 응답으로 보낸다. handlerrequestcallback과 함께 호출되며, requestscheme에 대한 들어오는 요청이다.

request를 처리하기 위해 callback은 파일 경로 또는 path 속성을 가진 객체와 함께 호출되어야 한다. 예를 들어 callback(filePath) 또는 callback({ path: filePath })와 같이 사용한다. filePath는 절대 경로여야 한다.

기본적으로 schemehttp:처럼 처리되며, 이는 file:과 같은 "일반 URI 구문"을 따르는 프로토콜과는 다르게 파싱된다.

protocol.registerBufferProtocol(scheme, handler) Deprecated

History

boolean을 반환 - 프로토콜이 성공적으로 등록되었는지 여부

Buffer를 응답으로 전송하는 scheme 프로토콜을 등록한다.

registerFileProtocol과 사용법이 동일하지만, callbackBuffer 객체 또는 data 속성을 가진 객체와 함께 호출해야 한다.

예제:

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

protocol.registerStringProtocol(scheme, handler) 사용 중단됨

History

boolean을 반환 - 프로토콜이 성공적으로 등록되었는지 여부

scheme 프로토콜을 등록하고, string을 응답으로 보낸다.

registerFileProtocol과 사용법이 동일하지만, callbackstring 또는 data 속성을 가진 객체와 함께 호출해야 한다.

protocol.registerHttpProtocol(scheme, handler) 더 이상 사용되지 않음

History

boolean을 반환 - 프로토콜이 성공적으로 등록되었는지 여부

scheme의 프로토콜을 등록하여 HTTP 요청을 응답으로 보낸다.

사용법은 registerFileProtocol과 동일하지만, callbackurl 속성을 가진 객체로 호출해야 한다.

protocol.registerStreamProtocol(scheme, handler) Deprecated

History

boolean을 반환한다. 프로토콜이 성공적으로 등록되었는지 여부를 나타낸다.

scheme 프로토콜을 등록하여 스트림을 응답으로 보낸다.

사용법은 registerFileProtocol과 동일하지만, callbackReadableStream 객체 또는 data 속성을 가진 객체와 함께 호출해야 한다.

예제:

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

function createStream (text) {
const rv = new PassThrough() // PassThrough는 Readable 스트림이다
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>')
})
})

data/end/error 이벤트를 발생시키는 읽기 가능한 스트림 API를 구현한 모든 객체를 전달할 수 있다. 예를 들어, 파일을 반환하는 방법은 다음과 같다:

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

protocol.unregisterProtocol(scheme) Deprecated

History
  • scheme string

boolean을 반환한다. 프로토콜이 성공적으로 등록 해제되었는지 여부를 나타낸다.

scheme에 해당하는 커스텀 프로토콜을 등록 해제한다.

protocol.isProtocolRegistered(scheme) 사용 중단됨

History
  • scheme string

boolean을 반환합니다. scheme이 이미 등록되었는지 여부를 나타냅니다.

protocol.interceptFileProtocol(scheme, handler) Deprecated

History

boolean을 반환한다 - 프로토콜이 성공적으로 인터셉트되었는지 여부

scheme 프로토콜을 인터셉트하고, handler를 프로토콜의 새로운 핸들러로 사용한다. 이 핸들러는 파일을 응답으로 보낸다.

protocol.interceptStringProtocol(scheme, handler) 더 이상 사용되지 않음

History

boolean을 반환 - 프로토콜이 성공적으로 가로채졌는지 여부

scheme 프로토콜을 가로채고 handler를 프로토콜의 새로운 핸들러로 사용하며, 응답으로 string을 보낸다.

protocol.interceptBufferProtocol(scheme, handler) Deprecated

History

반환값 boolean - 프로토콜이 성공적으로 인터셉트되었는지 여부

scheme 프로토콜을 인터셉트하고, handler를 새로운 프로토콜 핸들러로 사용하여 Buffer를 응답으로 보낸다.

protocol.interceptHttpProtocol(scheme, handler) Deprecated

History

boolean을 반환 - 프로토콜이 성공적으로 인터셉트되었는지 여부를 나타낸다.

schema 프로토콜을 인터셉트하고, handler를 프로토콜의 새로운 핸들러로 사용한다. 이 핸들러는 새로운 HTTP 요청을 응답으로 보낸다.

protocol.interceptStreamProtocol(scheme, handler) Deprecated

History

boolean을 반환 - 프로토콜이 성공적으로 가로채졌는지 여부

protocol.registerStreamProtocol과 동일하지만, 기존 프로토콜 핸들러를 대체한다.

protocol.uninterceptProtocol(scheme) Deprecated

History
  • scheme string

boolean을 반환 - 프로토콜의 인터셉트가 성공적으로 해제되었는지 여부

scheme에 설치된 인터셉터를 제거하고 원래 핸들러를 복원한다.

protocol.isProtocolIntercepted(scheme) 더 이상 사용되지 않음

History
  • scheme string

boolean을 반환 - scheme이 이미 인터셉트되었는지 여부를 나타냅니다.