You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Chrome插件中保留Notion SDK类型接口并规避CORS问题?

保留Notion SDK类型化接口的Chrome插件封装方案

由于CORS限制,Content Script无法直接调用Notion官方SDK,通过chrome.runtime.sendMessage通信会丢失原SDK的类型提示与简洁调用体验。以下是基于TypeScript的封装方案,可完全复用Notion SDK的类型系统,让调用方式和原代码保持一致。


1. 定义共享类型

创建跨Content Script和Background的共享类型文件,统一消息结构并复用Notion SDK的类型定义:

// types/notion-proxy.ts
import { Client } from "@notionhq/client";

// 定义代理消息结构
export type NotionProxyMessage = {
  type: "NOTION_PROXY_CALL";
  methodPath: string[]; // 例如 ["databases", "retrieve"]
  args: any[];
};

// 导出Notion Client类型,供Content Script端复用
export type NotionClient = Client;

2. Content Script端:创建Notion代理对象

实现一个代理类,模拟原Notion Client的结构,所有方法调用会自动转为消息发送到Background:

// content_script.tsx
import type { NotionClient, NotionProxyMessage } from "./types/notion-proxy";

export function createNotionProxy(): NotionClient {
  const createProxySegment = (path: string[]): any => {
    return new Proxy({}, {
      get(target, prop) {
        if (typeof prop === "string") {
          const newPath = [...path, prop];
          // 对方法调用进行拦截,转为消息发送
          return (...args: any[]) => {
            return new Promise((resolve, reject) => {
              chrome.runtime.sendMessage<NotionProxyMessage, any>(
                {
                  type: "NOTION_PROXY_CALL",
                  methodPath: newPath,
                  args,
                },
                (response) => {
                  if (chrome.runtime.lastError) {
                    reject(chrome.runtime.lastError);
                  } else {
                    resolve(response);
                  }
                }
              );
            });
          };
        }
        return createProxySegment([...path, prop as string]);
      },
    });
  };

  return createProxySegment([]) as NotionClient;
}

// 调用示例(和原SDK写法完全一致,保留自动补全)
async function saveToNotion() {
  const { notionToken } = await chrome.storage.local.get("notionToken");
  const notion = createNotionProxy();
  
  // 自动补全和类型检查正常工作
  const database = await notion.databases.retrieve({ database_id: "your-db-id" });
  console.log(database);
}

3. Background端:处理代理消息

监听Content Script发送的消息,解析方法路径并调用实际的Notion SDK方法:

// background.tsx
import { Client } from "@notionhq/client";
import type { NotionProxyMessage } from "./types/notion-proxy";

// 缓存Notion Client,避免重复初始化
let notionClient: Client | null = null;
async function getNotionClient(): Promise<Client> {
  if (!notionClient) {
    const { notionToken } = await chrome.storage.local.get("notionToken");
    notionClient = new Client({ auth: notionToken });
  }
  return notionClient;
}

// 监听代理消息并处理
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
  if (request.type === "NOTION_PROXY_CALL") {
    try {
      const client = await getNotionClient();
      // 按路径找到对应的SDK方法
      let targetMethod: any = client;
      for (const segment of request.methodPath) {
        targetMethod = targetMethod[segment];
      }
      // 调用方法并返回结果
      const result = await targetMethod(...request.args);
      sendResponse(result);
    } catch (error) {
      sendResponse({ error: (error as Error).message });
    }
    // 返回true保持异步通信通道打开
    return true;
  }
});

关键优势

  • 完全复用Notion SDK的类型定义,保留自动补全和类型检查能力
  • 无需手动编写每个接口的消息通信逻辑,大幅减少重复代码
  • 缓存Notion Client,避免重复初始化提升性能
  • 统一的错误处理机制,便于排查问题

内容的提问来源于stack exchange,提问作者David Davó

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:22:35