如何用Electron JS搭配React JS获取局域网已连接打印机名称列表
Electron + React 获取局域网已连接打印机列表最佳实践
核心思路:所有系统级API调用全部放在Electron主进程处理,通过安全IPC通道和React渲染层通信,优先使用Electron官方内置API,减少第三方依赖,兼顾安全性、跨平台兼容性和稳定性。
方案选型逻辑
不要一开始就写局域网端口扫描、跨平台调用系统命令的冗余逻辑,Electron官方已经封装了和系统打印模块打通的API,可以直接拿到系统枚举的所有可用打印机,包括本地直连、局域网共享、网络连接的设备,和系统打印面板展示的列表完全一致,拿到的设备都是已经安装驱动、可以直接发起打印的,比自己扫描出来的未安装驱动的设备实用性高很多。
- 核心API:Electron 11+ 版本内置的
webContents.getPrintersAsync(),异步非阻塞,支持Windows/macOS/Linux全平台 - 通信方式:基于
contextBridge做安全的IPC通信,不开启nodeIntegration,遵循Electron安全规范 - 扩展场景:如果需要识别还没被用户添加到系统的局域网打印机,再额外按平台加扫描逻辑即可
具体实现步骤
1. 主进程逻辑编写
在Electron主进程中注册IPC处理函数,统一处理打印机列表获取逻辑,不要把系统API直接暴露给渲染层。
const { ipcMain, BrowserWindow } = require('electron') const path = require('path') // 注册IPC处理通道 ipcMain.handle('fetch-network-printers', async () => { const currentWin = BrowserWindow.getFocusedWindow() if (!currentWin) return [] // 调用内置API获取全量打印机列表 const allPrinters = await currentWin.webContents.getPrintersAsync() // 按需过滤:只返回在线的局域网/网络打印机,过滤掉离线设备、虚拟打印机(如PDF导出、OneNote虚拟打印等) return allPrinters .filter(printer => { return printer.status !== 0 // 0代表离线 && printer.isNetworkPrinter // 只留网络/局域网打印机,要拿全量可以去掉这个条件 }) .map(printer => ({ name: printer.name, // 发起打印时直接传这个名称即可 displayName: printer.displayName, isShared: printer.isShared, location: printer.location })) }) // 主窗口初始化配置 function createMainWindow() { const mainWin = new BrowserWindow({ width: 1280, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, // *必须开启*,隔离渲染层和主进程上下文 nodeIntegration: false, // *必须关闭*,避免渲染层拿到全量node权限带来安全风险 sandbox: false } }) // 加载React页面,开发环境可以加载本地dev服务地址,生产环境加载打包后的html mainWin.loadURL(/* 你的React页面地址 */) }
如果需要获取未添加到系统的局域网打印机,再在主进程加对应平台的扫描逻辑,不要放到渲染层执行:
- Windows:通过PowerShell执行
Get-Printer命令枚举域内、局域网共享的打印设备 - macOS:通过
lpstat -p命令或者Bonjour服务扫描mDNS广播的打印设备 - Linux:通过
lpstat -a或者avahi服务扫描局域网打印设备
扫描到的结果和内置API拿到的已安装列表去重合并即可。
2. Preload预加载脚本配置
通过预加载脚本,只把需要的方法暴露给React渲染层,避免暴露过多系统能力:
const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('desktopAPI', { getPrinters: () => ipcRenderer.invoke('fetch-network-printers') })
3. React层调用
React侧不需要引入任何node相关依赖,直接调用预加载脚本暴露的全局方法即可:
import { useEffect, useState } from 'react' export default function PrinterSelect() { const [printerList, setPrinterList] = useState([]) const [activePrinter, setActivePrinter] = useState('') useEffect(() => { const getPrinters = async () => { const list = await window.desktopAPI.getPrinters() setPrinterList(list) } getPrinters() }, []) return ( <div className="printer-selector"> <label>选择局域网打印机:</label> <select value={activePrinter} onChange={e => setActivePrinter(e.target.value)} > {printerList.map(printer => ( <option key={printer.name} value={printer.name}> {printer.displayName} </option> ))} </select> </div> ) }
避坑说明
- 不要使用年久失修的第三方打印相关npm包(比如老旧的
electron-printer类库),这类包大多不支持新版Electron,跨平台bug多,没有维护价值,官方内置API稳定性最高 - 不要在React渲染层直接调用node模块或者执行系统命令,会打破Electron的安全隔离模型,容易出现权限报错和安全漏洞
- 如果遇到枚举不到目标打印机的情况,先检查系统自带的打印面板是否能看到该设备,Electron的枚举结果和系统打印面板完全一致,系统识别不到的设备Electron也无法获取
- 如果你的应用需要兼容Electron 11以下的老旧版本,可以把
getPrintersAsync()换成同步的webContents.getPrinters(),但同步API会阻塞主进程,不推荐使用
内容的提问来源于stack exchange,提问作者Rajashree Saste
相关产品推荐
相关产品推荐

