Files
ruoyi-java/doc/腾讯文档API读取失败诊断指南.md
2025-11-06 10:39:04 +08:00

397 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 腾讯文档 API 读取失败诊断指南
## 问题描述
当调用腾讯文档读取接口时,返回错误:
```json
{
"msg": "无法读取表头请检查headerRow参数",
"code": 500
}
```
请求参数:
```json
{
"fileId": "DUW50RUprWXh2TGJK",
"sheetId": "BB08J2",
"headerRow": 1,
"orderNoColumn": 3,
"logisticsLinkColumn": 13
}
```
---
## 已添加的调试功能
我已经在代码中添加了详细的日志记录,现在会输出以下信息:
### 1. Service 层日志
- 开始读取表格数据的参数
- 获取用户信息的响应
- Open ID 提取结果
- API 调用参数
- API 返回结果
### 2. Controller 层日志
- 读取表头的范围
- 表头数据的完整响应
- values 数组是否为空
---
## 诊断步骤
### 步骤 1查看应用日志
启用 DEBUG 级别日志:
**application-dev.yml**
```yaml
logging:
level:
com.ruoyi.jarvis.service.impl.TencentDocServiceImpl: DEBUG
com.ruoyi.jarvis.util.TencentDocApiUtil: DEBUG
com.ruoyi.web.controller.jarvis.TencentDocController: DEBUG
```
重启应用后,再次调用 API查看日志输出。
### 步骤 2分析日志信息
#### 2.1 检查用户信息获取
查找日志:
```
正在获取用户信息...
用户信息响应: {"ret":0,"msg":"Succeed","data":{...}}
```
**可能的问题**
- ❌ 如果看到 `401 Unauthorized`Access Token 无效或过期
- ❌ 如果看到 `ret != 0`:业务逻辑错误
- ❌ 如果 `data` 为 null响应格式不正确
**解决方案**
1. 检查 Access Token 是否有效
2. 使用 Refresh Token 刷新 Access Token
3. 重新进行 OAuth2 授权
#### 2.2 检查 Open ID 获取
查找日志:
```
成功获取 Open ID: bcb50c8a4b724d86bbcf6fc64c5e2b22
```
**可能的问题**
- ❌ 如果看到 `openID 字段不存在`:响应结构解析错误
- ❌ 如果 openID 为空:用户信息不完整
**解决方案**
1. 检查用户信息响应的完整内容
2. 确认响应格式是否为:`{"ret":0,"msg":"Succeed","data":{"openID":"xxx",...}}`
3. 注意字段名是 `openID`(大写 ID
#### 2.3 检查 API 调用
查找日志:
```
读取表格数据 - fileId: DUW50RUprWXh2TGJK, sheetId: BB08J2, range: A1:Z1, apiUrl: https://docs.qq.com/openapi/spreadsheet/v3/files/DUW50RUprWXh2TGJK/BB08J2/A1:Z1
```
**可能的问题**
- ❌ 如果看到 `404 Not Found`:文件 ID 或工作表 ID 错误
- ❌ 如果看到 `403 Forbidden`:没有访问权限
- ❌ 如果看到 `400 Bad Request`:请求参数格式错误
**解决方案**
1. **验证 File ID**
- 打开腾讯文档,从 URL 中获取正确的 File ID
- URL 格式:`https://docs.qq.com/sheet/DUW50RUprWXh2TGJK?tab=BB08J2`
- File ID 是 `sheet/` 后面到 `?` 之前的部分
2. **验证 Sheet ID**
- Sheet ID 是 URL 中 `tab=` 后面的部分
- 例如:`BB08J2`
3. **检查文档权限**
- 确认授权用户有权限访问该文档
- 在腾讯文档中检查分享设置
#### 2.4 检查 API 响应
查找日志:
```
表头数据响应: {"values":[["列1","列2","列3"]]}
```
```
表头数据中values数组为空完整响应: {...}
```
**可能的问题**
##### 问题 AAPI 返回成功但 values 为空
```json
{
"values": []
}
```
```json
{}
```
**原因**
1. 指定的行数据确实为空
2. Range 格式不正确
3. 权限不足,只能看到空数据
**解决方案**
1. 手动在腾讯文档中检查第 1 行是否有数据
2. 尝试不同的 range
- `A1:A1`(单个单元格)
- `A1:E1`(前 5 列)
- `A1`(从 A1 开始的所有数据)
##### 问题 BAPI 返回错误
可能的错误响应:
```json
{
"error": "invalid_token",
"error_description": "Invalid access token"
}
```
**原因**
- Access Token 无效或过期
- Open ID 不正确
- Client IDApp ID不正确
**解决方案**
1. 刷新 Access Token
2. 重新获取 Open ID
3. 检查配置文件中的 App ID
---
## 常见问题和解决方案
### 问题 1Access Token 过期
**症状**
```
getUserInfo 返回 401 Unauthorized
```
**解决方案**
```java
// 使用 Refresh Token 刷新 Access Token
JSONObject newTokens = tencentDocService.refreshAccessToken(refreshToken);
String newAccessToken = newTokens.getString("access_token");
String newRefreshToken = newTokens.getString("refresh_token");
// 保存新的 tokens
// ...
```
### 问题 2文档权限不足
**症状**
```
调用腾讯文档API失败: HTTP 403 Forbidden
```
**解决方案**
1. 在腾讯文档中打开该文档
2. 点击右上角"分享"按钮
3. 确认授权用户的微信/QQ 账号有访问权限
4. 如果是企业文档,需要确认企业权限设置
### 问题 3File ID 或 Sheet ID 错误
**症状**
```
调用腾讯文档API失败: HTTP 404 Not Found
```
**解决方案**
1. 重新从浏览器地址栏复制完整 URL
2. 正确提取 File ID 和 Sheet ID
```
URL: https://docs.qq.com/sheet/DUW50RUprWXh2TGJK?tab=BB08J2
↑ ↑
File ID Sheet ID
(18个字符) (6个字符)
```
3. File ID 通常以 `D` 开头,长度约 18 个字符
4. Sheet ID 通常是 6 个大写字母和数字的组合
### 问题 4Range 格式错误
**症状**
```
values 数组为空,但手动检查文档有数据
```
**可能的原因**
- Range 格式不符合腾讯文档 API 规范
- 行号从 0 开始而不是从 1 开始
**测试不同的 Range 格式**
```bash
# 测试 1单个单元格
curl "http://localhost:8080/api/test/read?fileId=XXX&sheetId=YYY&range=A1"
# 测试 2单行范围
curl "http://localhost:8080/api/test/read?fileId=XXX&sheetId=YYY&range=A1:Z1"
# 测试 3多行范围
curl "http://localhost:8080/api/test/read?fileId=XXX&sheetId=YYY&range=A1:Z10"
# 测试 4使用行号 0如果API是从0开始
curl "http://localhost:8080/api/test/read?fileId=XXX&sheetId=YYY&range=A0:Z0"
```
### 问题 5鉴权头设置错误
**症状**
```
调用腾讯文档API失败: HTTP 401 Unauthorized
```
**检查**
确认代码中使用了正确的鉴权方式:
```java
conn.setRequestProperty("Access-Token", accessToken);
conn.setRequestProperty("Client-Id", clientId);
conn.setRequestProperty("Open-Id", openId);
```
而不是:
```java
conn.setRequestProperty("Authorization", "Bearer " + accessToken); // ❌ 错误
```
---
## 快速诊断脚本
创建一个测试接口来诊断问题:
```java
@GetMapping("/test/diagnose")
public Map<String, Object> diagnose(@RequestParam String accessToken) {
Map<String, Object> result = new LinkedHashMap<>();
try {
// 1. 测试获取用户信息
System.out.println("\n=== 步骤1获取用户信息 ===");
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
result.put("1_userInfo", userInfo);
System.out.println("✓ 用户信息: " + userInfo.toJSONString());
// 2. 提取 Open ID
System.out.println("\n=== 步骤2提取 Open ID ===");
JSONObject data = userInfo.getJSONObject("data");
String openID = data != null ? data.getString("openID") : null;
result.put("2_openID", openID);
System.out.println("✓ Open ID: " + openID);
// 3. 测试读取文档
String testFileId = "DUW50RUprWXh2TGJK";
String testSheetId = "BB08J2";
String testRange = "A1:Z1";
System.out.println("\n=== 步骤3读取表格数据 ===");
System.out.println("File ID: " + testFileId);
System.out.println("Sheet ID: " + testSheetId);
System.out.println("Range: " + testRange);
JSONObject readResult = tencentDocService.readSheetData(
accessToken, testFileId, testSheetId, testRange
);
result.put("3_readResult", readResult);
System.out.println("✓ 读取结果: " + readResult.toJSONString());
// 4. 检查 values 数组
System.out.println("\n=== 步骤4检查 values 数组 ===");
JSONArray values = readResult != null ? readResult.getJSONArray("values") : null;
result.put("4_values", values);
result.put("4_valuesCount", values != null ? values.size() : 0);
System.out.println("✓ Values 数组大小: " + (values != null ? values.size() : 0));
if (values != null && !values.isEmpty()) {
System.out.println("✓ 第一行数据: " + values.getJSONArray(0).toJSONString());
}
result.put("status", "success");
result.put("message", "所有测试通过");
} catch (Exception e) {
result.put("status", "error");
result.put("error", e.getMessage());
result.put("stackTrace", Arrays.toString(e.getStackTrace()));
System.err.println("✗ 诊断失败: " + e.getMessage());
e.printStackTrace();
}
return result;
}
```
**使用方法**
```bash
curl "http://localhost:8080/test/diagnose?accessToken=YOUR_ACCESS_TOKEN"
```
---
## 检查清单
执行以下检查清单,确保所有配置正确:
### 配置检查
- [ ] `application-dev.yml``app-id` 配置正确
- [ ] `application-dev.yml``app-secret` 配置正确
- [ ] `application-dev.yml``api-base-url``https://docs.qq.com/openapi/spreadsheet/v3`
- [ ] 日志级别设置为 DEBUG
### 授权检查
- [ ] Access Token 未过期有效期3天
- [ ] 授权用户有访问该文档的权限
- [ ] 文档没有被删除或移动
### 参数检查
- [ ] File ID 正确(从 URL 中复制)
- [ ] Sheet ID 正确(从 URL 的 tab 参数中复制)
- [ ] headerRow 参数正确(通常为 1
- [ ] Range 格式正确(如 `A1:Z1`
### 代码检查
- [ ] 使用查询参数方式调用 `/oauth/v2/userinfo?access_token=xxx`
- [ ] 正确解析用户信息:`userInfo.getJSONObject("data").getString("openID")`
- [ ] 使用三个鉴权头:`Access-Token`, `Client-Id`, `Open-Id`
---
## 联系支持
如果以上步骤都无法解决问题,请提供以下信息:
1. **完整的日志输出**DEBUG 级别)
2. **请求参数**
- File ID
- Sheet ID
- Header Row
- Range
3. **腾讯文档 URL**(用于验证 ID 是否正确)
4. **错误信息**(完整的堆栈跟踪)
5. **用户信息响应**(脱敏后的 JSON
6. **API 调用响应**(完整的 JSON
---
**诊断指南版本**1.0
**创建时间**2025-11-05
**适用场景**:腾讯文档 API 读取失败问题排查