共计 2244 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:传统插件与 ChatGPT 插件的差异
传统网页插件通常采用 iframe 或 content script 方式嵌入,而 ChatGPT 侧边栏插件面临三个独特挑战:

- 跨域通信 :主应用与插件域名不同,需解决跨域资源访问(CORS) 问题
- 会话状态维护:对话上下文需在页面刷新后保持连贯性
- 双向实时交互:插件需要响应 GPT 生成内容并动态更新 UI
架构设计
@startuml
participant "ChatGPT 主应用" as main
participant "插件前端" as plugin
participant "认证服务" as auth
participant "业务 API" as api
auth -> plugin : OAuth2.0 授权码
plugin -> main : 携带 JWT 初始化
main -> plugin : 建立 WebSocket 连接
loop 消息交互
plugin -> main : JSON-RPC 请求
main -> api : 数据查询
api -> main : 返回结果
main -> plugin : 推送更新
end
@enduml
核心模块说明
- 鉴权流程
- 使用 OAuth2.0 授权码模式获取 access_token
-
JWT 中需包含用户 ID、会话 ID、权限 scope
-
通信协议
- WebSocket 保持长连接
-
JSON-RPC 规范消息格式:
interface RpcMessage { id: string; method: 'query' | 'update'; params: unknown; } -
上下文存储
- IndexedDB 存储历史会话
- LRU 缓存最近 5 条对话上下文
代码实现
基础消息类实现
class MessageClient {
private ws: WebSocket;
private retryCount = 0;
constructor(url: string) {this.connect(url);
}
private connect(url: string) {this.ws = new WebSocket(url);
this.ws.onclose = () => {if(this.retryCount < 3) {setTimeout(() => this.connect(url), 1000 * 2 ** this.retryCount++);
}
};
}
send(message: RpcMessage): Promise<unknown> {return new Promise((resolve, reject) => {const timeout = setTimeout(() => reject('Timeout'), 5000);
this.ws.send(JSON.stringify({
...message,
id: crypto.randomUUID()}));
this.ws.onmessage = (evt) => {clearTimeout(timeout);
resolve(JSON.parse(evt.data));
};
});
}
}
DOM 注入示例
function renderSidebar(content: HTMLElement) {const sidebar = document.querySelector('#chatgpt-sidebar');
if (!sidebar) {const container = document.createElement('div');
container.id = 'chatgpt-sidebar';
Object.assign(container.style, {
position: 'fixed',
right: '0',
top: '0',
width: '300px',
height: '100vh',
zIndex: '9999'
});
document.body.appendChild(container);
container.appendChild(content);
}
}
生产环境考量
性能优化
| 方案 | 内存占用 | CPU 负载 | 延迟 |
|---|---|---|---|
| 长轮询 | 较高 | 波动大 | 1-3s |
| WebSocket | 稳定 | 平稳 | <100ms |
安全措施
- XSS 防护
- 所有动态内容使用 DOMPurify 过滤
- CSP 策略限制外部资源加载
- 数据脱敏
function maskSensitive(text: string) {return text.replace(/\b\d{4}\b/g, '****'); }
监控体系
- 关键指标埋点:
- 消息往返时延
- WebSocket 重连次数
- 用户交互事件
- Sentry 捕获前端异常
常见问题解决
- 会话 ID 冲突
-
解决方案:在 JWT 中嵌入浏览器指纹
import FingerprintJS from '@fingerprintjs/fingerprintjs'; const fp = await FingerprintJS.load(); const {visitorId} = await fp.get(); -
高频消息限流
-
实现令牌桶算法:
class RateLimiter { private tokens = 10; async acquire() {if(this.tokens > 0) { this.tokens--; return true; } await new Promise(r => setTimeout(r, 1000)); return this.acquire();} } -
Chrome 扩展兼容
- 在 manifest.json 中声明最低版本:
{ "minimum_chrome_version": "88", "manifest_version": 3 }
延伸阅读
正文完
发表至: 未分类
近两天内
