Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ demo/
.ice/
scripts/
locale/
dist/

# node 覆盖率文件
coverage/
Expand Down
10 changes: 5 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ module.exports = getESLintConfig('react-ts', {
{
'pattern': '@/**',
'group': 'parent',
'position': 'before'
}
'position': 'before',
},
],
'pathGroupsExcludedImportTypes': ['builtin'],
'newlines-between': 'never'
}
]
'newlines-between': 'never',
},
],
},
});
166 changes: 166 additions & 0 deletions DEBUG_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Header Editor V3 调试指南

## 问题:请求网址时没有添加 x-tag header

### 🔍 调试步骤

#### 1. 检查规则是否已创建
首先确认您是否已经正确创建了添加 x-tag header 的规则:

**在 Header Editor 选项页面:**
1. 打开 Chrome 扩展管理页面 (`chrome://extensions/`)
2. 找到 Header Editor,点击"详细信息"
3. 点击"扩展程序选项"
4. 检查是否有类似以下的规则:
- 规则类型:修改发送头
- 头名称:x-tag (或 X-Tag)
- 头内容:您想要的值
- 匹配类型:全部(或特定模式)
- 启用状态:✅ 已启用

#### 2. 使用调试工具检查规则状态
打开浏览器开发者工具 (F12),在 Console 中执行:

```javascript
// 检查 x-tag 规则的完整状态
testXTagHeaderRule()
```

这个命令将:
- 检查当前的规则
- 如果没有 x-tag 规则,自动创建一个测试规则
- 验证规则转换是否正确
- 检查 V3 规则是否正确应用

#### 3. 检查扩展是否被禁用
```javascript
// 检查扩展是否被禁用
chrome.runtime.sendMessage({method: 'getRuleStats'})
```

#### 4. 启用调试日志
```javascript
// 启用详细的调试日志
chrome.runtime.sendMessage({method: 'enableDebugLogging'})
```

启用后,刷新页面并查看控制台输出,查找相关的规则应用信息。

#### 5. 验证规则是否生效
访问 https://httpbin.org/headers 来检查请求头:

1. 打开 https://httpbin.org/headers
2. 查看返回的 JSON 中的 `headers` 字段
3. 检查是否包含您的 x-tag header

**或者在开发者工具中检查:**
1. 打开开发者工具 (F12)
2. 切换到 Network 标签
3. 刷新页面
4. 点击任意请求
5. 在 Headers 标签中查看 Request Headers
6. 查找您的 x-tag header

### 🚨 常见问题和解决方案

#### 问题 1:规则存在但没有生效
**可能原因:**
- 规则转换失败
- V3 规则没有正确应用
- 匹配条件不正确

**解决方案:**
```javascript
// 强制刷新规则
chrome.runtime.sendMessage({method: 'testRuleApplication'})
```

#### 问题 2:规则转换失败
**可能原因:**
- 规则格式不正确
- 包含不支持的功能

**解决方案:**
确保规则满足以下条件:
- 规则类型为 `modifySendHeader`
- 不使用自定义函数 (`isFunction: false`)
- Header 名称和值都不为空

#### 问题 3:V3 规则限制
**可能原因:**
- Chrome 的 declarativeNetRequest 有一些限制

**解决方案:**
- 确保 header 名称符合 HTTP 规范
- 避免使用特殊字符
- 检查是否超过规则数量限制

### 🔧 手动创建测试规则

如果自动创建不工作,可以手动创建:

1. 打开 Header Editor 选项页面
2. 点击"添加规则"
3. 填写以下信息:
- 名称:`测试 X-Tag Header`
- 规则类型:`修改发送头`
- 匹配类型:`全部`
- 执行类型:`普通`
- 头名称:`X-Tag`
- 头内容:`test-value`
4. 点击保存

### 📊 检查规则统计

```javascript
// 获取当前规则统计
chrome.runtime.sendMessage({method: 'getRuleStats'}).then(response => {
console.log('规则统计:', response.stats);
});

// 获取当前应用的 V3 规则
chrome.declarativeNetRequest.getDynamicRules().then(rules => {
console.log('当前 V3 规则:', rules);
const headerRules = rules.filter(rule =>
rule.action.type === 'modifyHeaders' &&
rule.action.requestHeaders
);
console.log('修改请求头的规则:', headerRules);
});
```

### 🔍 深度调试

如果上述步骤都没有解决问题,请:

1. **收集调试信息:**
```javascript
// 收集完整的调试信息
const debugInfo = {
rules: await chrome.runtime.sendMessage({method: 'getRuleStats'}),
v3Rules: await chrome.declarativeNetRequest.getDynamicRules(),
permissions: await chrome.permissions.getAll()
};
console.log('调试信息:', debugInfo);
```

2. **检查权限:**
确保扩展有以下权限:
- `declarativeNetRequest`
- `declarativeNetRequestWithHostAccess`
- 相关的主机权限

3. **检查浏览器版本:**
确保使用 Chrome 88+ 或其他支持 Manifest V3 的浏览器

### 📝 报告问题

如果问题仍然存在,请提供以下信息:

1. 浏览器版本
2. Header Editor 版本
3. 创建的规则详情
4. 调试输出结果
5. 期望的行为 vs 实际行为

这将帮助我们更好地诊断和解决问题。
151 changes: 151 additions & 0 deletions MIGRATION_REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Header Editor Manifest V3 迁移报告

## 项目概述
Header Editor 是一个浏览器扩展,允许用户修改 HTTP 请求和响应头。本项目已完成从 Manifest V2 到 Manifest V3 的迁移。

## 最新修复 (2024-12-19)

### 问题诊断
经过代码审查发现以下关键问题:
1. **规则更新事件监听缺失** - 规则变化时没有自动重新应用 V3 规则
2. **规则转换逻辑不完善** - V3RuleConverter 存在类型错误和转换不准确
3. **初始化时序问题** - 数据库未完全准备好就开始应用规则
4. **调试信息不足** - 缺少详细的调试日志来排查问题

### 修复内容

#### 1. 事件监听系统 (src/pages/background/index.ts)
- ✅ 添加规则更新事件监听 (`EVENTs.RULE_UPDATE`, `EVENTs.RULE_DELETE`)
- ✅ 添加偏好设置变化监听 (`disable-all` 设置)
- ✅ 改进初始化流程,等待数据库和规则缓存完全准备
- ✅ 添加自动规则刷新机制
- ✅ 添加测试接口和调试命令

#### 2. 规则转换器优化 (src/pages/background/v3-rule-converter.ts)
- ✅ 修复类型定义问题,使用正确的 declarativeNetRequest 类型
- ✅ 改进规则验证逻辑,确保生成的 V3 规则有效
- ✅ 优化资源类型设置,移除不支持的类型
- ✅ 添加批量规则应用,避免一次性应用过多规则
- ✅ 改进错误处理和日志记录
- ✅ 添加规则转换详细日志记录

#### 3. API 处理器增强 (src/pages/background/api-handler.ts)
- ✅ 在所有规则操作后自动触发 V3 规则刷新
- ✅ 添加详细的操作日志记录
- ✅ 改进错误处理和状态反馈
- ✅ 添加规则统计信息接口

#### 4. 日志系统升级 (src/share/core/logger.ts)
- ✅ 重构日志系统,支持不同日志级别
- ✅ 添加专用的规则转换日志方法
- ✅ 添加性能统计日志
- ✅ 添加扩展状态日志
- ✅ 改进日志格式和上下文信息

### 核心改进

#### 自动规则同步
现在规则的任何变化都会自动触发 V3 规则的重新应用:
- 创建新规则 → 自动应用到 declarativeNetRequest
- 修改现有规则 → 自动更新 declarativeNetRequest
- 删除规则 → 自动从 declarativeNetRequest 移除
- 偏好设置变化 → 自动调整规则应用状态

#### 规则转换改进
- 更准确的规则类型识别和转换
- 更严格的规则验证
- 更好的错误处理和回退机制
- 更详细的转换统计和日志

#### 调试和测试功能
- 可通过 console 调用 `testRuleApplication()` 进行测试
- 支持动态启用/禁用调试日志
- 提供详细的规则转换和应用统计
- 支持获取当前规则状态和转换结果

## 主要变化说明

### 1. 网络请求处理
- **V2**: 使用 `chrome.webRequest` API 进行实时拦截和修改
- **V3**: 使用 `chrome.declarativeNetRequest` API 进行声明式规则处理

### 2. 背景脚本
- **V2**: 持久化背景页面 (`background.html`)
- **V3**: 服务工作者 (`background.js`)

### 3. 权限系统
- **V2**: `webRequestBlocking` 权限
- **V3**: `declarativeNetRequest` 和 `declarativeNetRequestWithHostAccess` 权限

### 4. 规则应用方式
- **V2**: 运行时动态处理每个请求
- **V3**: 预配置规则集,由浏览器引擎处理

## 功能限制

### 不支持的功能
1. **自定义 JavaScript 函数规则** - V3 不允许执行任意代码
2. **响应体修改** - declarativeNetRequest 不支持响应体修改
3. **复杂正则表达式** - V3 API 对正则表达式有限制
4. **动态 IP 获取** - 无法在 V3 中获取客户端 IP

### 功能替代方案
- 简单的头部修改 → 使用 `modifyHeaders` 动作
- URL 重定向 → 使用 `redirect` 动作
- 请求阻止 → 使用 `block` 动作
- 域名匹配 → 使用 `domains` 条件

## 测试验证

### 测试方法
1. 打开浏览器开发者工具
2. 切换到 Console 标签
3. 执行 `testRuleApplication()` 进行功能测试
4. 检查规则转换统计和应用结果

### 测试内容
- 规则转换正确性
- 规则应用成功率
- 事件监听响应
- 错误处理能力
- 性能表现

## 部署建议

### 开发环境
- 启用调试日志: `chrome.runtime.sendMessage({method: 'enableDebugLogging'})`
- 运行测试: `testRuleApplication()`
- 检查规则统计: `chrome.runtime.sendMessage({method: 'getRuleStats'})`

### 生产环境
- 默认使用 INFO 级别日志
- 定期检查规则应用状态
- 监控转换失败的规则

## 后续工作建议

1. **用户体验优化**
- 添加规则转换失败的用户提示
- 提供规则迁移建议
- 改进错误消息的用户友好性

2. **功能增强**
- 支持更多的 URL 匹配模式
- 优化规则优先级管理
- 添加规则冲突检测

3. **性能优化**
- 优化大量规则的处理性能
- 减少规则应用的延迟
- 改进内存使用

4. **稳定性改进**
- 增强错误恢复机制
- 添加规则备份和恢复功能
- 提高扩展的崩溃恢复能力

## 结论

本次修复解决了 Header Editor 在 Manifest V3 环境下的核心问题,确保了规则的正确转换和应用。通过完善的事件监听、详细的日志记录和自动化测试,显著提升了扩展的稳定性和可维护性。

虽然 V3 的限制导致部分高级功能无法使用,但对于大多数用户的基本需求(请求头修改、URL 重定向、请求阻止等),扩展已能够正常工作。
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "header-editor",
"version": "5.0.0",
"version": "6.0.0",
"description": "Header Editor",
"author": "ShuangYa",
"license": "GPL-2.0",
Expand Down
10 changes: 5 additions & 5 deletions scripts/webpack/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports = function (config, context) {
// 调试模式下,开启自动重载和自动编译
if (config.get('mode') === 'development') {
// config.plugin('reload').use(ChromeExtensionReloader);
config.devServer.hot(false);
config.devServer.hot(true);
config.devServer.open(false);
const devMiddleware = config.devServer.store.get('devMiddleware');
config.devServer.store.set('devMiddleware', {
Expand All @@ -13,10 +13,10 @@ module.exports = function (config, context) {
});
}

config.plugin('bundle-analyzer').use(new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: '../temp/bundle-analyze.html',
}))
// config.plugin('bundle-analyzer').use(new BundleAnalyzerPlugin({
// analyzerMode: 'static',
// reportFilename: '../temp/bundle-analyze.html',
// }))

return config;
};
2 changes: 1 addition & 1 deletion scripts/webpack/remove-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = function (config, context) {
continue;
}
const pageName = item.name.substr(18);
if (pageName === 'background' || pageName.indexOf('inject-') === 0 || pageName.indexOf('worker-') === 0) {
if (pageName === 'content' || pageName === 'background' || pageName.indexOf('inject-') === 0 || pageName.indexOf('worker-') === 0) {
config.plugins.delete(item.name);
console.log('Remove html entry: ' + item.name);
}
Expand Down
Loading