docs/archives/119-csp-safe-template-processing/technical-details.md
浏览器扩展环境中存在严格的内容安全策略(CSP)限制,禁止使用 unsafe-eval。这导致 Handlebars.compile() 无法在浏览器扩展中正常工作,因为它在内部使用了 Function 构造函数或 eval() 来动态编译模板。
OptimizationError: Optimization failed: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
我们实现了一个CSP兼容的模板处理器,专门用于浏览器扩展环境:
位置:packages/core/src/services/template/csp-safe-processor.ts
功能特性:
{{variable}} 变量替换eval() 或 Function 构造函数支持的语法:
{{variableName}} - 基本变量替换{{ variableName }} - 带空格的变量{{originalPrompt}}、{{lastOptimizedPrompt}}、{{iterateInput}}不支持的语法:
{{#if condition}} - 条件语句{{#each items}} - 循环语句{{#unless condition}} - 否定条件{{> partial}} - 部分模板{{{unescaped}}} - 非转义输出TemplateProcessor 会自动检测运行环境:
// 检测是否在浏览器扩展环境中
if (CSPSafeTemplateProcessor.isExtensionEnvironment()) {
// 使用CSP安全的处理器
return CSPSafeTemplateProcessor.processContent(msg.content, context);
} else {
// 使用完整的Handlebars功能
return Handlebars.compile(msg.content, { noEscape: true })(context);
}
static isExtensionEnvironment(): boolean {
try {
return typeof chrome !== 'undefined' &&
typeof chrome.runtime !== 'undefined' &&
typeof chrome.runtime.getManifest === 'function';
} catch (error) {
return false;
}
}
const content = 'Hello {{name}}, you are {{age}} years old.';
const context = { name: 'Alice', age: '25' };
const result = CSPSafeTemplateProcessor.processContent(content, context);
// 结果: "Hello Alice, you are 25 years old."
const content = 'Original: {{originalPrompt}}, Input: {{iterateInput}}';
const context = {
originalPrompt: 'Write a story',
iterateInput: 'Make it more dramatic'
};
const result = CSPSafeTemplateProcessor.processContent(content, context);
// 结果: "Original: Write a story, Input: Make it more dramatic"
| 环境 | 模板引擎 | 功能支持 |
|---|---|---|
| 浏览器扩展 | CSPSafeTemplateProcessor | 基本变量替换 |
| Web应用 | Handlebars | 完整功能 |
| Desktop应用 | Handlebars | 完整功能 |
相关测试文件:
packages/core/tests/unit/template/csp-safe-processor.test.tspackages/core/tests/unit/template/extension-environment.test.ts运行测试:
cd packages/core
npm test -- csp-safe-processor.test.ts
npm test -- extension-environment.test.ts
packages/core/src/services/template/csp-safe-processor.ts - CSP安全处理器packages/core/src/services/template/processor.ts - 主模板处理器(已修改)packages/extension/public/manifest.json - 扩展清单文件(CSP配置)问题演进: 原本的环境特定方案虽然解决了CSP问题,但维护了两套不同的模板处理逻辑,增加了系统复杂性。
最终解决方案:
isExtensionEnvironment() 判断逻辑CSPSafeTemplateProcessor,统一使用 Mustache.render()技术优势:
实现对比:
// 旧方案:环境判断
if (CSPSafeTemplateProcessor.isExtensionEnvironment()) {
return CSPSafeTemplateProcessor.processContent(msg.content, context);
} else {
return Handlebars.compile(msg.content, { noEscape: true })(context);
}
// 新方案:统一处理
return Mustache.render(msg.content, context);
迁移结果:
csp-safe-processor.ts, csp-safe-processor.test.tshandlebars → mustache这次迁移将CSP安全处理从"兼容性方案"升级为"原生支持方案",是架构简化的重要里程碑。