Skip to main content
  1. 所有文章/

小记 | 使用 Hono 简化 Electron 自定义协议处理

·1015 words·3 mins

前情提要 #

阅读本文需要对 ElectronHono 以及 Service Worker 等技术有一定了解

引入 #

开发 Electron 应用的都知道,在其模块 protocol 中提供了一个方法protocol.registerSchemesAsPrivileged(customSchemes) 用于自定义协议

而后,可以通过 protocol.handle(scheme, handler) 1对请求进行处理

本文所说的,即发生在 handler

正文 #

一般写法如下

app.whenReady().then(() => {
  protocol.handle("app", (req) => {
    const { host, pathname } = new URL(req.url);
    if (host === "bundle") {
      if (pathname === "/") {
        return new Response("hello, world!"});
      }
    }
  });
});

熟悉 Service Worker 的都知道,在 SW 中也有一个 FetchEvent,用于拦截请求并自定义响应,其写法大致(省略部分代码)如下

self.addEventListener("fetch", (event) => {
    event.respondWith(new Response("hello, world!"));
});

这样可能不能说明什么,但如果我们将响应提到 handler 中呢?

const fetchHandler = () => {
	return new Response("hello, world!");
};

self.addEventListener("fetch", (event) => {
    event.respondWith(fetchHandler());
});

这时候,我们发现 handler 部分就和 protocol.handlehandler 一致了

既然它们很相像,那么 Service Worker 上的 handler 是不是也能给 Electron 用?

这时候,我突然想起 Hono 这个框架,它不也是 handler 么?

而且 Hono 用起来更加简洁,还支持链式路由,比写一大堆 if-else 好多了

于是,我就尝试用 Hono 来作为 protocol.handlehandler

尝试适配 #

理所当然,我们应该查看 Hono 文档中关于 Service Worker 适配器 的部分,文档中 self.addEventListener('fetch', handle(app))handle(app) 就是 handler

定位到 handle 函数的来源:src/adapter/service-worker/handler.ts

其实最后就是传入了一个类型为 Hono 的对象 app,调用 app.fetch()

而 Hono 文档:App - Hono - Hono 的解释:「 app.fetch will be entry point of your application. 」也说明 app.fetch 就是我们需要的东西

所以,直接传入 Request2就好了

……吗?

我们简单变换代码,并把 Hono 的逻辑移到 protocolHandler.js

// main.js
import { app, protocol } from "electron";
import { protocolApp } from "./utils/protocolHandler.js";

app.whenReady().then(() => {
  protocol.handle("app", async (req) => {
      await protocolApp.fetch(req);
  });
});

// protocolHandler.js
import { Hono } from "hono";

const app = new Hono();

app.get("/bundle/", (c) => {
    return c.text("hello, world!");
});

export const protocolApp = app;

请求 app://bundle/,会发现得到 404,是 Hono 没生效吗?但是我们如果定义 notFound

app.notFound((c) => {
  return c.text(`You're trying to get response from: ${c.req.path}, But it's undefined.`, 404);
});

会发现 Hono 已经成功处理了请求,但是为什么还是 404?

我们看看响应:You're trying to get response from: //bundle/, But it's undefined.

咦,路由怎么变成这样了,关键点在 //bundle/,我们想要访问 app://bundle/ 能被 Hono 响应,那我们将路由修改为 //bundle/ 呢?

发现 Hono 能够响应了,但是每次这样写路由也太阴间了,所以我们需要简化一下

通过输出日志判断,Honomacaron: 删除,把 //bundle/ 当作 path,因此,只需要指定 Hono 的工作路径(basePath)就可以解决

basePath 不能为 /,因为 Hono 默认路径就是 /,不知道为什么需要写阴间路由

不过我们可以指定 basePath//

const app = new Hono().basePath("//");

然后修改路由

app.get('bundle/', async (c) => {
  return c.text('hello, world!');
});

请求,发现完美解决问题

又是麻烦的一天呢😡

参考 #