652 lines
16 KiB
Markdown
652 lines
16 KiB
Markdown
# 存储访问问题
|
||
|
||
<cite>
|
||
**本文档引用的文件**
|
||
- [TsStorage.js](file://src/utils/TsStorage.js)
|
||
- [TsCommon.js](file://src/utils/TsCommon.js)
|
||
- [TsHttpUtil.js](file://src/https/TsHttpUtil.js)
|
||
- [TsCrypto.js](file://src/utils/TsCrypto.js)
|
||
- [TsSM4.js](file://src/utils/TsSM4.js)
|
||
- [TsGlobalConfig.js](file://src/utils/TsGlobalConfig.js)
|
||
- [index.js](file://index.js)
|
||
- [package.json](file://package.json)
|
||
- [README.md](file://README.md)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构概览](#架构概览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [存储访问故障排除指南](#存储访问故障排除指南)
|
||
7. [依赖关系分析](#依赖关系分析)
|
||
8. [性能考虑](#性能考虑)
|
||
9. [故障排除指南](#故障排除指南)
|
||
10. [结论](#结论)
|
||
|
||
## 简介
|
||
|
||
本指南专注于存储访问相关的故障排除,涵盖localStorage访问失败、数据读取错误、存储空间不足、数据格式异常等问题的诊断和解决方法。该工具包提供了完整的本地存储解决方案,包括数据序列化、加密存储、错误处理等功能。
|
||
|
||
## 项目结构
|
||
|
||
该项目采用模块化设计,主要包含以下核心模块:
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "主入口"
|
||
Index[index.js]
|
||
end
|
||
subgraph "存储模块"
|
||
Storage[TsStorage.js]
|
||
Common[TsCommon.js]
|
||
end
|
||
subgraph "网络模块"
|
||
HttpUtil[TsHttpUtil.js]
|
||
Crypto[TsCrypto.js]
|
||
SM4[TsSM4.js]
|
||
Config[TsGlobalConfig.js]
|
||
end
|
||
subgraph "外部依赖"
|
||
UmiRequest[umi-request]
|
||
Base64[base64-js]
|
||
end
|
||
Index --> Storage
|
||
Index --> HttpUtil
|
||
Index --> Crypto
|
||
Index --> Config
|
||
Storage --> Common
|
||
HttpUtil --> Storage
|
||
HttpUtil --> Crypto
|
||
Crypto --> SM4
|
||
Crypto --> Config
|
||
HttpUtil --> UmiRequest
|
||
Crypto --> Base64
|
||
```
|
||
|
||
**图表来源**
|
||
- [index.js:1-16](file://index.js#L1-L16)
|
||
- [TsStorage.js:1-55](file://src/utils/TsStorage.js#L1-L55)
|
||
- [TsHttpUtil.js:1-171](file://src/https/TsHttpUtil.js#L1-L171)
|
||
|
||
**章节来源**
|
||
- [index.js:1-16](file://index.js#L1-L16)
|
||
- [package.json:1-24](file://package.json#L1-L24)
|
||
|
||
## 核心组件
|
||
|
||
### 存储管理器 (TsStorage)
|
||
|
||
存储管理器提供了完整的localStorage操作接口,支持数据的保存、读取和用户令牌管理。
|
||
|
||
**主要功能特性:**
|
||
- 数据序列化和反序列化
|
||
- 用户令牌存储和获取
|
||
- 加密开关控制
|
||
- 错误处理和默认值机制
|
||
|
||
### 通用工具 (TsCommon)
|
||
|
||
提供了基础的JavaScript工具函数,特别是JSON解析和数据验证功能。
|
||
|
||
**关键功能:**
|
||
- 安全的JSON解析
|
||
- 空值检测
|
||
- 字符串处理工具
|
||
|
||
### 网络请求 (TsHttpUtil)
|
||
|
||
集成了存储功能的HTTP客户端,支持自动数据加密和令牌管理。
|
||
|
||
**核心特性:**
|
||
- 自动令牌注入
|
||
- 条件数据加密
|
||
- 统一错误处理
|
||
- 配置化参数处理
|
||
|
||
## 架构概览
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as 客户端应用
|
||
participant Storage as 存储管理器
|
||
participant Common as 通用工具
|
||
participant Crypto as 加密模块
|
||
participant HTTP as HTTP客户端
|
||
Client->>Storage : 保存数据
|
||
Storage->>Storage : 序列化数据
|
||
Storage->>Storage : 写入localStorage
|
||
Client->>Storage : 读取数据
|
||
Storage->>Storage : 从localStorage读取
|
||
Storage->>Common : 解析JSON
|
||
Common-->>Storage : 返回数据
|
||
Storage-->>Client : 返回结果
|
||
Client->>HTTP : 发送请求
|
||
HTTP->>Storage : 获取用户令牌
|
||
Storage-->>HTTP : 返回令牌
|
||
HTTP->>Crypto : 加密数据(可选)
|
||
Crypto-->>HTTP : 返回加密结果
|
||
HTTP-->>Client : 返回响应
|
||
```
|
||
|
||
**图表来源**
|
||
- [TsStorage.js:26-43](file://src/utils/TsStorage.js#L26-L43)
|
||
- [TsCommon.js:29-44](file://src/utils/TsCommon.js#L29-L44)
|
||
- [TsHttpUtil.js:99-134](file://src/https/TsHttpUtil.js#L99-L134)
|
||
|
||
## 详细组件分析
|
||
|
||
### 存储组件深度分析
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class TsStorage {
|
||
+save(key, value) void
|
||
+get(key, def) string
|
||
+saveUserToken(token) void
|
||
+getUserToken() string
|
||
+saveEncryptBody(bool) void
|
||
+getEncryptBody() boolean
|
||
}
|
||
class TsCommon {
|
||
+parseJSON(value, def) Object
|
||
+isEmpty(value) boolean
|
||
+getParamFormUrl(key, host) string
|
||
+isDevelopment() boolean
|
||
}
|
||
class TsHttpUtil {
|
||
+req(url, options) Promise
|
||
+get(url, params, options) Promise
|
||
+post(url, data, options) Promise
|
||
+form(url, data, options) Promise
|
||
}
|
||
class TsCrypto {
|
||
+encrypt(content) string
|
||
+decrypt(base64) string
|
||
}
|
||
class TsSM4 {
|
||
+encrypt(plaintext) string
|
||
+decrypt(ciphertext) string
|
||
}
|
||
TsStorage --> TsCommon : 使用
|
||
TsHttpUtil --> TsStorage : 依赖
|
||
TsHttpUtil --> TsCrypto : 使用
|
||
TsCrypto --> TsSM4 : 使用
|
||
```
|
||
|
||
**图表来源**
|
||
- [TsStorage.js:26-54](file://src/utils/TsStorage.js#L26-L54)
|
||
- [TsCommon.js:89-97](file://src/utils/TsCommon.js#L89-L97)
|
||
- [TsHttpUtil.js:168-170](file://src/https/TsHttpUtil.js#L168-L170)
|
||
- [TsCrypto.js:5-33](file://src/utils/TsCrypto.js#L5-L33)
|
||
|
||
**章节来源**
|
||
- [TsStorage.js:1-55](file://src/utils/TsStorage.js#L1-L55)
|
||
- [TsCommon.js:1-98](file://src/utils/TsCommon.js#L1-L98)
|
||
- [TsHttpUtil.js:1-171](file://src/https/TsHttpUtil.js#L1-L171)
|
||
|
||
## 存储访问故障排除指南
|
||
|
||
### 常见存储问题诊断
|
||
|
||
#### 1. localStorage 访问失败
|
||
|
||
**症状表现:**
|
||
- 页面加载时报错,提示localStorage不可用
|
||
- 数据无法保存或读取
|
||
- 浏览器控制台出现安全错误
|
||
|
||
**诊断步骤:**
|
||
1. 检查浏览器隐私模式设置
|
||
2. 验证跨域访问权限
|
||
3. 确认浏览器扩展程序影响
|
||
4. 检查HTTPS环境要求
|
||
|
||
**解决方案:**
|
||
```javascript
|
||
// 检查localStorage可用性
|
||
function checkLocalStorage() {
|
||
try {
|
||
const test = 'test';
|
||
localStorage.setItem(test, test);
|
||
localStorage.removeItem(test);
|
||
return true;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 降级方案:使用sessionStorage
|
||
if (!checkLocalStorage()) {
|
||
console.warn('localStorage不可用,使用sessionStorage作为替代');
|
||
}
|
||
```
|
||
|
||
#### 2. 数据读取错误
|
||
|
||
**症状表现:**
|
||
- 读取到空值或undefined
|
||
- JSON解析失败
|
||
- 数据类型不匹配
|
||
|
||
**诊断流程:**
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([开始诊断]) --> CheckKey["检查键名是否存在"]
|
||
CheckKey --> KeyExists{"键存在?"}
|
||
KeyExists --> |否| CreateDefault["创建默认值"]
|
||
KeyExists --> |是| CheckFormat["检查数据格式"]
|
||
CheckFormat --> FormatOK{"格式正确?"}
|
||
FormatOK --> |否| ParseError["JSON解析错误"]
|
||
FormatOK --> |是| DataType["检查数据类型"]
|
||
DataType --> TypeOK{"类型匹配?"}
|
||
TypeOK --> |否| ConvertData["转换数据类型"]
|
||
TypeOK --> |是| Success["诊断完成"]
|
||
CreateDefault --> Success
|
||
ParseError --> FixParse["修复JSON格式"]
|
||
FixParse --> Success
|
||
ConvertData --> Success
|
||
```
|
||
|
||
**图表来源**
|
||
- [TsStorage.js:41-43](file://src/utils/TsStorage.js#L41-L43)
|
||
- [TsCommon.js:34-44](file://src/utils/TsCommon.js#L34-L44)
|
||
|
||
**解决方案:**
|
||
1. 实施默认值机制
|
||
2. 添加数据类型验证
|
||
3. 实现错误边界处理
|
||
|
||
#### 3. 存储空间不足
|
||
|
||
**症状表现:**
|
||
- 保存数据时报错
|
||
- 随机数据丢失
|
||
- 性能明显下降
|
||
|
||
**诊断方法:**
|
||
1. 检查localStorage使用量
|
||
2. 分析数据增长趋势
|
||
3. 识别大体积数据项
|
||
|
||
**优化策略:**
|
||
```javascript
|
||
// 存储容量监控
|
||
function checkStorageCapacity() {
|
||
const storage = localStorage;
|
||
let totalSize = 0;
|
||
|
||
for (let key in storage) {
|
||
if (storage.hasOwnProperty(key)) {
|
||
totalSize += storage[key].length;
|
||
}
|
||
}
|
||
|
||
return totalSize;
|
||
}
|
||
|
||
// 清理过期数据
|
||
function cleanupExpiredData() {
|
||
const now = Date.now();
|
||
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7天
|
||
|
||
for (let key in localStorage) {
|
||
if (localStorage.hasOwnProperty(key)) {
|
||
try {
|
||
const item = JSON.parse(localStorage.getItem(key));
|
||
if (item.timestamp && (now - item.timestamp) > maxAge) {
|
||
localStorage.removeItem(key);
|
||
}
|
||
} catch (e) {
|
||
// 忽略格式错误的数据
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4. 数据格式异常
|
||
|
||
**症状表现:**
|
||
- JSON解析抛出异常
|
||
- 数据损坏或不完整
|
||
- 版本升级后数据不兼容
|
||
|
||
**诊断步骤:**
|
||
1. 验证数据完整性
|
||
2. 检查版本兼容性
|
||
3. 分析数据结构变化
|
||
|
||
**修复方法:**
|
||
```javascript
|
||
// 安全的数据读取
|
||
function safeGet(key, defaultValue = null) {
|
||
try {
|
||
const item = localStorage.getItem(key);
|
||
if (!item) return defaultValue;
|
||
|
||
const parsed = JSON.parse(item);
|
||
return parsed.data || defaultValue;
|
||
} catch (error) {
|
||
console.error(`读取存储项 ${key} 失败:`, error);
|
||
return defaultValue;
|
||
}
|
||
}
|
||
|
||
// 数据格式验证
|
||
function validateDataStructure(data) {
|
||
const requiredFields = ['data'];
|
||
return requiredFields.every(field => data.hasOwnProperty(field));
|
||
}
|
||
```
|
||
|
||
### 浏览器兼容性问题
|
||
|
||
#### 1. 不同浏览器的差异
|
||
|
||
**问题类型:**
|
||
- Safari隐私模式限制
|
||
- IE/Edge兼容性问题
|
||
- 移动端存储限制
|
||
|
||
**解决方案:**
|
||
```javascript
|
||
// 跨浏览器兼容性检查
|
||
function isStorageSupported() {
|
||
const testKey = '__storage_test__';
|
||
|
||
try {
|
||
if ('localStorage' in window && window['localStorage'] !== null) {
|
||
localStorage.setItem(testKey, testKey);
|
||
localStorage.removeItem(testKey);
|
||
return true;
|
||
}
|
||
return false;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 功能检测而非浏览器检测
|
||
function getStorageImplementation() {
|
||
if (isStorageSupported()) {
|
||
return localStorage;
|
||
} else if (typeof sessionStorage !== 'undefined') {
|
||
return sessionStorage;
|
||
} else {
|
||
// 无存储支持,使用内存存储
|
||
return createMemoryStorage();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 存储权限限制
|
||
|
||
**常见场景:**
|
||
- 第三方Cookie限制
|
||
- HTTPS环境要求
|
||
- 用户隐私设置
|
||
|
||
**处理策略:**
|
||
```javascript
|
||
// 权限检查和降级
|
||
function handleStoragePermissions() {
|
||
const permissions = {
|
||
localStorage: false,
|
||
sessionStorage: false,
|
||
cookies: false
|
||
};
|
||
|
||
// 检查localStorage
|
||
try {
|
||
localStorage.setItem('permission_test', 'test');
|
||
localStorage.removeItem('permission_test');
|
||
permissions.localStorage = true;
|
||
} catch (e) {
|
||
permissions.localStorage = false;
|
||
}
|
||
|
||
// 检查cookies
|
||
try {
|
||
document.cookie = 'permission_test=test';
|
||
permissions.cookies = true;
|
||
} catch (e) {
|
||
permissions.cookies = false;
|
||
}
|
||
|
||
return permissions;
|
||
}
|
||
```
|
||
|
||
### 数据序列化失败
|
||
|
||
#### 1. JSON序列化问题
|
||
|
||
**常见原因:**
|
||
- 循环引用
|
||
- 函数和undefined
|
||
- 复杂对象类型
|
||
|
||
**诊断方法:**
|
||
```mermaid
|
||
flowchart TD
|
||
Start([序列化开始]) --> CheckCircular["检查循环引用"]
|
||
CheckCircular --> HasCircular{"存在循环引用?"}
|
||
HasCircular --> |是| RemoveCircular["移除循环引用"]
|
||
HasCircular --> |否| CheckTypes["检查数据类型"]
|
||
CheckTypes --> HasInvalid{"包含无效类型?"}
|
||
HasInvalid --> |是| FilterInvalid["过滤无效类型"]
|
||
HasInvalid --> |否| SafeStringify["安全字符串化"]
|
||
RemoveCircular --> SafeStringify
|
||
FilterInvalid --> SafeStringify
|
||
SafeStringify --> Complete["序列化完成"]
|
||
```
|
||
|
||
**图表来源**
|
||
- [TsStorage.js:31-33](file://src/utils/TsStorage.js#L31-L33)
|
||
|
||
**解决方案:**
|
||
```javascript
|
||
// 安全的JSON序列化
|
||
function safeStringify(obj) {
|
||
const seen = new WeakSet();
|
||
|
||
return JSON.stringify(obj, (key, value) => {
|
||
if (typeof value === "object" && value !== null) {
|
||
if (seen.has(value)) {
|
||
return "[Circular Reference]";
|
||
}
|
||
seen.add(value);
|
||
}
|
||
return value;
|
||
});
|
||
}
|
||
|
||
// 自定义序列化器
|
||
function customSerializer(data) {
|
||
return {
|
||
data: data,
|
||
timestamp: Date.now(),
|
||
version: "1.0"
|
||
};
|
||
}
|
||
```
|
||
|
||
## 依赖关系分析
|
||
|
||
```mermaid
|
||
graph LR
|
||
subgraph "核心依赖"
|
||
A[umi-request] --> B[TsHttpUtil]
|
||
C[base64-js] --> D[TsCrypto]
|
||
end
|
||
subgraph "内部模块"
|
||
E[TsStorage] --> F[TsCommon]
|
||
B --> E
|
||
B --> G[TsCrypto]
|
||
G --> H[TsSM4]
|
||
G --> I[TsGlobalConfig]
|
||
end
|
||
J[index.js] --> E
|
||
J --> B
|
||
J --> G
|
||
J --> I
|
||
```
|
||
|
||
**图表来源**
|
||
- [package.json:19-22](file://package.json#L19-L22)
|
||
- [index.js:1-16](file://index.js#L1-L16)
|
||
|
||
**章节来源**
|
||
- [package.json:1-24](file://package.json#L1-L24)
|
||
- [index.js:1-16](file://index.js#L1-L16)
|
||
|
||
## 性能考虑
|
||
|
||
### 存储性能优化
|
||
|
||
1. **批量操作优化**
|
||
- 合并多个存储操作
|
||
- 使用事务性操作
|
||
- 避免频繁的读写
|
||
|
||
2. **数据压缩**
|
||
- 对大对象进行压缩
|
||
- 实现增量更新
|
||
- 使用索引优化查询
|
||
|
||
3. **缓存策略**
|
||
- 实现内存缓存
|
||
- 设置合理的过期时间
|
||
- 支持LRU淘汰算法
|
||
|
||
### 数据迁移最佳实践
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([开始迁移]) --> CheckVersion["检查当前版本"]
|
||
CheckVersion --> VersionOK{"版本兼容?"}
|
||
VersionOK --> |是| DirectCopy["直接复制数据"]
|
||
VersionOK --> |否| TransformData["转换数据格式"]
|
||
TransformData --> ValidateData["验证数据完整性"]
|
||
DirectCopy --> ValidateData
|
||
ValidateData --> MigrationOK{"迁移成功?"}
|
||
MigrationOK --> |是| UpdateVersion["更新版本号"]
|
||
MigrationOK --> |否| Rollback["回滚操作"]
|
||
UpdateVersion --> Complete["迁移完成"]
|
||
Rollback --> Complete
|
||
```
|
||
|
||
**图表来源**
|
||
- [TsStorage.js:41-43](file://src/utils/TsStorage.js#L41-L43)
|
||
|
||
## 故障排除指南
|
||
|
||
### 常见错误信息解读
|
||
|
||
| 错误类型 | 可能原因 | 解决方案 |
|
||
|---------|---------|---------|
|
||
| SecurityError | 跨域访问限制 | 检查域名和协议一致性 |
|
||
| QuotaExceededError | 存储空间不足 | 清理旧数据或使用压缩 |
|
||
| InvalidStateError | 存储状态异常 | 重启浏览器或清除缓存 |
|
||
| TypeError | 数据格式错误 | 实施数据验证和转换 |
|
||
|
||
### 诊断工具和方法
|
||
|
||
```javascript
|
||
// 存储状态检查
|
||
function diagnoseStorage() {
|
||
const diagnostics = {
|
||
localStorage: false,
|
||
sessionStorage: false,
|
||
quota: 0,
|
||
items: 0,
|
||
totalSize: 0
|
||
};
|
||
|
||
// 检查localStorage
|
||
try {
|
||
localStorage.setItem('diagnostics', 'test');
|
||
localStorage.removeItem('diagnostics');
|
||
diagnostics.localStorage = true;
|
||
} catch (e) {
|
||
diagnostics.localStorage = false;
|
||
}
|
||
|
||
// 检查存储配额和使用情况
|
||
if (navigator.webkitTemporaryStorage) {
|
||
navigator.webkitTemporaryStorage.queryUsageAndQuota(
|
||
(usage, quota) => {
|
||
diagnostics.quota = quota;
|
||
diagnostics.used = usage;
|
||
}
|
||
);
|
||
}
|
||
|
||
// 统计存储项数量和大小
|
||
for (let key in localStorage) {
|
||
if (localStorage.hasOwnProperty(key)) {
|
||
diagnostics.items++;
|
||
diagnostics.totalSize += key.length + localStorage[key].length;
|
||
}
|
||
}
|
||
|
||
return diagnostics;
|
||
}
|
||
|
||
// 数据完整性验证
|
||
function validateStorageIntegrity() {
|
||
const errors = [];
|
||
const keys = Object.keys(localStorage);
|
||
|
||
keys.forEach(key => {
|
||
try {
|
||
JSON.parse(localStorage.getItem(key));
|
||
} catch (e) {
|
||
errors.push({
|
||
key: key,
|
||
error: e.message,
|
||
value: localStorage.getItem(key)
|
||
});
|
||
}
|
||
});
|
||
|
||
return errors;
|
||
}
|
||
```
|
||
|
||
### 最佳实践建议
|
||
|
||
1. **错误处理**
|
||
- 实施全面的try-catch包装
|
||
- 提供优雅降级机制
|
||
- 记录详细的错误日志
|
||
|
||
2. **数据保护**
|
||
- 实施数据备份策略
|
||
- 使用版本控制
|
||
- 定期数据健康检查
|
||
|
||
3. **性能监控**
|
||
- 监控存储使用率
|
||
- 跟踪访问模式
|
||
- 优化热点数据
|
||
|
||
**章节来源**
|
||
- [TsStorage.js:1-55](file://src/utils/TsStorage.js#L1-L55)
|
||
- [TsCommon.js:1-98](file://src/utils/TsCommon.js#L1-L98)
|
||
- [TsHttpUtil.js:1-171](file://src/https/TsHttpUtil.js#L1-L171)
|
||
|
||
## 结论
|
||
|
||
存储访问问题的解决需要系统性的方法和完善的监控机制。通过实施本文档提供的诊断流程、故障排除方法和最佳实践,可以有效预防和解决大多数存储相关问题。关键在于建立完善的错误处理机制、实施数据验证和转换、以及持续监控存储状态。
|
||
|
||
建议在生产环境中:
|
||
- 实施多层次的错误处理
|
||
- 建立存储使用监控
|
||
- 定期进行数据完整性检查
|
||
- 制定数据迁移和备份策略
|
||
|
||
这样可以确保应用程序的稳定性和可靠性,为用户提供更好的体验。 |