feat(admin): 增加崩溃报告联调信息展示
This commit is contained in:
@@ -11,6 +11,9 @@
|
||||
2. 后端模板化改造说明.md
|
||||
面向后端维护,说明当前 FastAPI 后端如何按 routes/services/repositories/schemas 分层,以及后续工程化方向。
|
||||
|
||||
3. 崩溃报告接口联调说明.md
|
||||
面向测试和客户端接入,说明 CRASH_REPORT_TOKEN、CRASH_SYMBOL_TOKEN、CRASH_ADMIN_TOKEN 分别怎么用,并给出可直接复制的 curl 示例。
|
||||
|
||||
常用源码入口:
|
||||
|
||||
- main.py:服务启动、数据库初始化、MinIO 初始化、全局客户端鉴权。
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
# SimCAE 崩溃报告接口联调说明
|
||||
|
||||
本文说明崩溃报告后端接口怎么测试,以及 curl 示例里的 `dev-token` 应该替换成什么。
|
||||
|
||||
## 一、先搞清楚三个 Token
|
||||
|
||||
curl 示例里的:
|
||||
|
||||
```text
|
||||
Authorization: Bearer dev-token
|
||||
```
|
||||
|
||||
这里的 `dev-token` 只是占位符,不是固定值。实际要按接口用途替换成服务端 `.env` / `.env.docker.example` 里的 token。
|
||||
|
||||
| 使用场景 | 请求头里填什么 | 服务端配置字段 |
|
||||
| --- | --- | --- |
|
||||
| 客户端上传崩溃报告 | `Authorization: Bearer <CRASH_REPORT_TOKEN>` | `CRASH_REPORT_TOKEN` |
|
||||
| 上传符号包 | `Authorization: Bearer <CRASH_SYMBOL_TOKEN>` | `CRASH_SYMBOL_TOKEN` |
|
||||
| 查询/下载崩溃报告原始文件 | `Authorization: Bearer <CRASH_ADMIN_TOKEN>` | `CRASH_ADMIN_TOKEN` |
|
||||
| `CRASH_ADMIN_TOKEN` 为空时查询/下载 | `Authorization: Bearer <ADMIN_TOKEN>` | `ADMIN_TOKEN` |
|
||||
|
||||
当前默认配置通常是:
|
||||
|
||||
```env
|
||||
CRASH_REPORT_TOKEN=SimCAECrashReportToken2026
|
||||
CRASH_SYMBOL_TOKEN=SimCAESymbolToken2026
|
||||
CRASH_ADMIN_TOKEN=
|
||||
ADMIN_TOKEN=SimCAEAdminToken2026
|
||||
```
|
||||
|
||||
所以,如果使用默认配置:
|
||||
|
||||
- 上传崩溃报告用 `SimCAECrashReportToken2026`。
|
||||
- 上传符号包用 `SimCAESymbolToken2026`。
|
||||
- 查询/下载崩溃报告时,因为 `CRASH_ADMIN_TOKEN` 为空,所以用 `SimCAEAdminToken2026`。
|
||||
|
||||
管理后台“客户端配置生成”区域下方也会显示“崩溃报告接口联调信息”。这部分只给管理员或测试人员查看,不会复制进客户端 `app_config.json`,也不要手动放进客户端配置文件。
|
||||
|
||||
其中会以类似 `.env` 的形式把 `CRASH_REPORT_TOKEN`、`CRASH_SYMBOL_TOKEN`、`CRASH_ADMIN_TOKEN`、`ADMIN_TOKEN` 单独列出来,并在每个字段前加中文说明。`CRASH_ADMIN_TOKEN` 如果为空,查询和下载崩溃报告时就使用 `ADMIN_TOKEN`。
|
||||
|
||||
## 二、接口地址
|
||||
|
||||
假设服务端地址是:
|
||||
|
||||
```text
|
||||
http://192.168.1.158:8000
|
||||
```
|
||||
|
||||
下面示例里用变量表示:
|
||||
|
||||
```bash
|
||||
SERVER=http://192.168.1.158:8000
|
||||
REPORT_TOKEN=SimCAECrashReportToken2026
|
||||
SYMBOL_TOKEN=SimCAESymbolToken2026
|
||||
ADMIN_TOKEN=SimCAEAdminToken2026
|
||||
```
|
||||
|
||||
如果部署了 HTTPS 或域名,把 `SERVER` 改成实际地址即可。
|
||||
|
||||
## 三、健康检查
|
||||
|
||||
健康检查不需要 token:
|
||||
|
||||
```bash
|
||||
curl "$SERVER/api/v1/health"
|
||||
```
|
||||
|
||||
正常返回类似:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "simcae-crash-server",
|
||||
"version": "1.0.0",
|
||||
"timeUtc": "2026-07-14T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## 四、准备测试文件
|
||||
|
||||
创建一个假的 minidump 文件:
|
||||
|
||||
```bash
|
||||
printf "dummy minidump for api test\n" > crash.dmp
|
||||
```
|
||||
|
||||
附件是可选的。需要测试附件时可以准备一个 zip:
|
||||
|
||||
```bash
|
||||
mkdir -p attachments
|
||||
printf "extra log\n" > attachments/runtime.log
|
||||
zip -r attachments.zip attachments
|
||||
```
|
||||
|
||||
如果服务器上没有 `zip`,可以先不传 `attachments` 字段。
|
||||
|
||||
## 五、准备 metadata.json
|
||||
|
||||
`clientReportId` 必须是 UUID,并且请求头 `Idempotency-Key` 必须和它完全一致。
|
||||
|
||||
最小可用示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"clientReportId": "8f6c5ed9-9a2b-4ef1-89a2-8843f2f7d9d1",
|
||||
"crashTimeUtc": "2026-07-14T08:30:00Z",
|
||||
"product": "SIMCAE",
|
||||
"appVersion": "0.10.3",
|
||||
"gitCommit": "unknown",
|
||||
"buildType": "Release",
|
||||
"channel": "stable",
|
||||
"platform": {
|
||||
"os": "Windows",
|
||||
"arch": "x64"
|
||||
},
|
||||
"crash": {
|
||||
"exceptionCode": "0xC0000005",
|
||||
"threadId": 1
|
||||
},
|
||||
"userConsent": {
|
||||
"uploadAllowed": true
|
||||
},
|
||||
"files": []
|
||||
}
|
||||
```
|
||||
|
||||
保存成 `metadata.json`。
|
||||
|
||||
说明:
|
||||
|
||||
- `product` 必须是 `SIMCAE`。
|
||||
- `schemaVersion` 必须是数字 `1`。
|
||||
- `files` 必须是数组,可以先填空数组。
|
||||
- 如果 `files` 里声明了 `minidump` 的 `sha256`,服务端会校验它必须和实际上传的 `crash.dmp` 一致。
|
||||
|
||||
## 六、上传崩溃报告
|
||||
|
||||
不带附件的最小上传:
|
||||
|
||||
```bash
|
||||
curl -X POST "$SERVER/api/v1/crash-reports" \
|
||||
-H "Authorization: Bearer $REPORT_TOKEN" \
|
||||
-H "Idempotency-Key: 8f6c5ed9-9a2b-4ef1-89a2-8843f2f7d9d1" \
|
||||
-H "X-SimCAE-Client: SIMCAE" \
|
||||
-H "X-SimCAE-Version: 0.10.3" \
|
||||
-F "metadata=@metadata.json;type=application/json" \
|
||||
-F "minidump=@crash.dmp;type=application/octet-stream"
|
||||
```
|
||||
|
||||
带附件上传:
|
||||
|
||||
```bash
|
||||
curl -X POST "$SERVER/api/v1/crash-reports" \
|
||||
-H "Authorization: Bearer $REPORT_TOKEN" \
|
||||
-H "Idempotency-Key: 8f6c5ed9-9a2b-4ef1-89a2-8843f2f7d9d1" \
|
||||
-H "X-SimCAE-Client: SIMCAE" \
|
||||
-H "X-SimCAE-Version: 0.10.3" \
|
||||
-F "metadata=@metadata.json;type=application/json" \
|
||||
-F "minidump=@crash.dmp;type=application/octet-stream" \
|
||||
-F "attachments=@attachments.zip;type=application/zip"
|
||||
```
|
||||
|
||||
正常首次上传返回 HTTP 201,类似:
|
||||
|
||||
```json
|
||||
{
|
||||
"reportId": "srv_xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"duplicate": false,
|
||||
"status": "stored",
|
||||
"acceptedAtUtc": "2026-07-14T08:31:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
如果用同一个 `clientReportId` 和相同内容重复上传,会返回 HTTP 200,并且:
|
||||
|
||||
```json
|
||||
{
|
||||
"duplicate": true
|
||||
}
|
||||
```
|
||||
|
||||
如果同一个 `clientReportId` 但内容变了,会返回 HTTP 409,表示幂等冲突。
|
||||
|
||||
## 七、查询崩溃报告详情
|
||||
|
||||
把上传返回的 `reportId` 填到下面命令里:
|
||||
|
||||
```bash
|
||||
REPORT_ID=srv_xxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
curl "$SERVER/api/v1/crash-reports/$REPORT_ID" \
|
||||
-H "Authorization: Bearer $ADMIN_TOKEN"
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- 这里用的是管理查询 token。
|
||||
- 如果 `.env` 里配置了 `CRASH_ADMIN_TOKEN`,就用 `CRASH_ADMIN_TOKEN`。
|
||||
- 如果 `CRASH_ADMIN_TOKEN` 为空,就用 `ADMIN_TOKEN`。
|
||||
|
||||
## 八、下载崩溃报告文件
|
||||
|
||||
可下载文件名:
|
||||
|
||||
```text
|
||||
metadata.json
|
||||
crash.dmp
|
||||
attachments.zip
|
||||
server.json
|
||||
```
|
||||
|
||||
下载 minidump:
|
||||
|
||||
```bash
|
||||
curl "$SERVER/api/v1/crash-reports/$REPORT_ID/files/crash.dmp" \
|
||||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||||
-o crash_downloaded.dmp
|
||||
```
|
||||
|
||||
下载 metadata:
|
||||
|
||||
```bash
|
||||
curl "$SERVER/api/v1/crash-reports/$REPORT_ID/files/metadata.json" \
|
||||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||||
-o metadata_downloaded.json
|
||||
```
|
||||
|
||||
管理后台也可以查看崩溃报告列表和下载文件。
|
||||
|
||||
## 九、上传符号包
|
||||
|
||||
符号包接口用于上传某个版本/构建对应的 symbols.zip。
|
||||
|
||||
准备 `symbols_metadata.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"product": "SIMCAE",
|
||||
"appVersion": "0.10.3",
|
||||
"gitCommit": "unknown",
|
||||
"buildType": "Release",
|
||||
"platform": "windows-x64",
|
||||
"toolchain": "msvc2019",
|
||||
"createdAtUtc": "2026-07-14T08:00:00Z",
|
||||
"files": []
|
||||
}
|
||||
```
|
||||
|
||||
准备测试符号包:
|
||||
|
||||
```bash
|
||||
mkdir -p symbols
|
||||
printf "dummy symbols\n" > symbols/readme.txt
|
||||
zip -r symbols.zip symbols
|
||||
```
|
||||
|
||||
上传:
|
||||
|
||||
```bash
|
||||
curl -X POST "$SERVER/api/v1/symbols" \
|
||||
-H "Authorization: Bearer $SYMBOL_TOKEN" \
|
||||
-F "metadata=@symbols_metadata.json;type=application/json" \
|
||||
-F "symbols=@symbols.zip;type=application/zip"
|
||||
```
|
||||
|
||||
正常返回类似:
|
||||
|
||||
```json
|
||||
{
|
||||
"symbolUploadId": "sym_xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"status": "stored",
|
||||
"duplicate": false,
|
||||
"acceptedAtUtc": "2026-07-14T08:35:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## 十、常见错误
|
||||
|
||||
1. HTTP 401 `missing bearer token`
|
||||
没有传 `Authorization: Bearer ...`,或者格式写错。
|
||||
|
||||
2. HTTP 401 `invalid bearer token`
|
||||
token 值不对。检查 `.env` 里的 `CRASH_REPORT_TOKEN`、`CRASH_SYMBOL_TOKEN`、`CRASH_ADMIN_TOKEN`、`ADMIN_TOKEN`。
|
||||
|
||||
3. HTTP 403 `token is not allowed to access this endpoint`
|
||||
token 是对的,但用错接口了。例如拿 `CRASH_REPORT_TOKEN` 去查询/下载报告。
|
||||
|
||||
4. HTTP 400 `Idempotency-Key must equal metadata.clientReportId`
|
||||
请求头 `Idempotency-Key` 必须等于 metadata 里的 `clientReportId`。
|
||||
|
||||
5. HTTP 400 `metadata.product must be SIMCAE`
|
||||
metadata 里的 `product` 必须填 `SIMCAE`。
|
||||
|
||||
6. HTTP 400 `file_hash_mismatch`
|
||||
metadata.files 里声明的 SHA-256 和实际上传文件不一致。联调初期可以先把 `files` 填成空数组。
|
||||
|
||||
7. HTTP 413 `payload_too_large`
|
||||
文件超过 `.env` 里的大小限制,例如 `CRASH_MINIDUMP_MAX_MB`、`CRASH_ATTACHMENTS_MAX_MB`、`CRASH_REQUEST_MAX_MB`。
|
||||
|
||||
8. HTTP 409 `idempotency_conflict`
|
||||
同一个 `clientReportId` 已经上传过,但这次内容不一样。换一个新的 UUID 再试。
|
||||
@@ -240,6 +240,8 @@ MinIO 控制台: http://你的服务器IP:9001/
|
||||
| `CRASH_REQUEST_MAX_MB` | 必填 | 可以 | 崩溃报告完整请求最大大小。 |
|
||||
| `CRASH_SYMBOLS_MAX_MB` | 必填 | 可以 | 符号文件最大大小。 |
|
||||
|
||||
崩溃报告上传、查询、下载、符号包上传的 curl 联调步骤见 `Docs/崩溃报告接口联调说明.md`。示例里的 `dev-token` 不是固定值,要按接口用途替换为 `CRASH_REPORT_TOKEN`、`CRASH_SYMBOL_TOKEN` 或 `CRASH_ADMIN_TOKEN` / `ADMIN_TOKEN`。
|
||||
|
||||
## 五、客户端配置要同步哪些值
|
||||
|
||||
推荐直接使用后台页面生成:
|
||||
|
||||
@@ -27,6 +27,7 @@ const auditLogs = ref<any[]>([]);
|
||||
const currentAppId = ref("");
|
||||
const createdLicenseKey = ref("");
|
||||
const generatedClientConfig = ref("");
|
||||
const generatedCrashTestInfo = ref("");
|
||||
const runtime = reactive<any>({});
|
||||
|
||||
const appForm = reactive({ app_id: "", app_name: "" });
|
||||
@@ -526,6 +527,9 @@ async function generateClientConfig() {
|
||||
});
|
||||
generatedClientConfig.value =
|
||||
result.json_text || JSON.stringify(result.config || {}, null, 2);
|
||||
generatedCrashTestInfo.value =
|
||||
result.crash_test_text ||
|
||||
JSON.stringify(result.crash_test_config || {}, null, 2);
|
||||
ElMessage.success("客户端配置已生成");
|
||||
} catch (error) {
|
||||
handleError("生成客户端配置失败", error);
|
||||
@@ -537,6 +541,11 @@ async function copyGeneratedConfig() {
|
||||
ElMessage.success("客户端配置已复制");
|
||||
}
|
||||
|
||||
async function copyGeneratedCrashTestInfo() {
|
||||
await copyText(generatedCrashTestInfo.value);
|
||||
ElMessage.success("崩溃报告联调信息已复制");
|
||||
}
|
||||
|
||||
async function loadDevices() {
|
||||
if (!currentAppId.value) return;
|
||||
const data = await adminRequest<any>(
|
||||
@@ -917,7 +926,11 @@ onMounted(loadAll);
|
||||
<el-form-item label="License"><el-input v-model="configForm.license_key" placeholder="可从上方 License 列表填入;也可留空让客户端首次启动时输入" /></el-form-item>
|
||||
</el-form>
|
||||
<div class="action-row"><el-button type="primary" @click="generateClientConfig">生成配套配置</el-button><el-button :disabled="!generatedClientConfig" @click="copyGeneratedConfig">复制配置</el-button></div>
|
||||
<div class="config-section-title">客户端 app_config.json</div>
|
||||
<pre class="code-block">{{ generatedClientConfig || "尚未生成客户端配置" }}</pre>
|
||||
<el-alert class="mt-sm" type="warning" :closable="false" show-icon title="下面的崩溃报告联调信息只给管理员或测试人员查看,不会复制进客户端 app_config.json,也不要放进客户端配置文件。" />
|
||||
<div class="action-row mt-sm"><span class="config-section-title">崩溃报告接口联调信息</span><el-button :disabled="!generatedCrashTestInfo" @click="copyGeneratedCrashTestInfo">复制联调信息</el-button></div>
|
||||
<pre class="code-block">{{ generatedCrashTestInfo || "生成配套配置后显示崩溃报告接口、Token 和大小限制" }}</pre>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
|
||||
@@ -1144,6 +1157,19 @@ onMounted(loadAll);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.config-section-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
margin: 12px 0 6px;
|
||||
color: var(--el-text-color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.action-row .config-section-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
min-height: 220px;
|
||||
max-height: 440px;
|
||||
|
||||
@@ -15,6 +15,8 @@ from app.services.admin_config_service import (
|
||||
TARGET_ARCH,
|
||||
TARGET_PLATFORM,
|
||||
default_client_config_values,
|
||||
crash_report_test_values,
|
||||
crash_report_test_text,
|
||||
normalize_executable_name,
|
||||
public_api_base_url,
|
||||
)
|
||||
@@ -104,7 +106,10 @@ def admin_generate_client_config(body: ClientConfigGenerateRequest, request: Req
|
||||
"platform": defaults["platform"],
|
||||
"arch": defaults["arch"],
|
||||
}
|
||||
crash_test_config = crash_report_test_values(api_base_url)
|
||||
return {
|
||||
"config": config,
|
||||
"json_text": json.dumps(config, ensure_ascii=False, indent=2),
|
||||
"crash_test_config": crash_test_config,
|
||||
"crash_test_text": crash_report_test_text(api_base_url),
|
||||
}
|
||||
|
||||
@@ -52,6 +52,116 @@ def default_client_config_values(request: Request) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def crash_report_test_values(api_base_url: str) -> dict:
|
||||
base_url = api_base_url.rstrip("/")
|
||||
crash_admin_token = os.getenv("CRASH_ADMIN_TOKEN", "").strip()
|
||||
admin_token = os.getenv("ADMIN_TOKEN", "").strip()
|
||||
crash_report_token = (
|
||||
os.getenv("CRASH_REPORT_TOKEN")
|
||||
or os.getenv("SIMCAE_CRASH_CLIENT_TOKEN")
|
||||
or os.getenv("CLIENT_API_TOKEN")
|
||||
or ""
|
||||
)
|
||||
crash_symbol_token = os.getenv("CRASH_SYMBOL_TOKEN") or os.getenv("SIMCAE_SYMBOL_TOKEN") or ""
|
||||
effective_admin_token = crash_admin_token or admin_token
|
||||
effective_admin_token_source = "CRASH_ADMIN_TOKEN" if crash_admin_token else "ADMIN_TOKEN"
|
||||
return {
|
||||
"说明": "仅用于后台管理员/测试人员联调崩溃报告接口,不要复制进客户端 app_config.json。",
|
||||
"server_base_url": base_url,
|
||||
"tokens": {
|
||||
"CRASH_REPORT_TOKEN": {
|
||||
"用途": "上传崩溃报告 /api/v1/crash-reports",
|
||||
"token": crash_report_token,
|
||||
},
|
||||
"CRASH_SYMBOL_TOKEN": {
|
||||
"用途": "上传符号包 /api/v1/symbols",
|
||||
"token": crash_symbol_token,
|
||||
},
|
||||
"CRASH_ADMIN_TOKEN": {
|
||||
"用途": "查询和下载崩溃报告",
|
||||
"token": crash_admin_token,
|
||||
"说明": "如果为空,查询/下载接口会使用 ADMIN_TOKEN。",
|
||||
},
|
||||
"ADMIN_TOKEN": {
|
||||
"用途": "管理后台令牌;当 CRASH_ADMIN_TOKEN 为空时也用于查询/下载崩溃报告",
|
||||
"token": admin_token,
|
||||
},
|
||||
},
|
||||
"upload_crash_report": {
|
||||
"url": f"{base_url}/api/v1/crash-reports",
|
||||
"authorization_header": "Authorization: Bearer <CRASH_REPORT_TOKEN>",
|
||||
"token_env": "CRASH_REPORT_TOKEN",
|
||||
"token": crash_report_token,
|
||||
"idempotency_key_rule": "Idempotency-Key 必须等于 metadata.clientReportId",
|
||||
},
|
||||
"upload_symbols": {
|
||||
"url": f"{base_url}/api/v1/symbols",
|
||||
"authorization_header": "Authorization: Bearer <CRASH_SYMBOL_TOKEN>",
|
||||
"token_env": "CRASH_SYMBOL_TOKEN",
|
||||
"token": crash_symbol_token,
|
||||
},
|
||||
"admin_query_and_download": {
|
||||
"detail_url_template": f"{base_url}/api/v1/crash-reports/{{report_id}}",
|
||||
"file_url_template": f"{base_url}/api/v1/crash-reports/{{report_id}}/files/{{file_name}}",
|
||||
"authorization_header": f"Authorization: Bearer <{effective_admin_token_source}>",
|
||||
"token_env": effective_admin_token_source,
|
||||
"token": effective_admin_token,
|
||||
"file_name_examples": ["metadata.json", "crash.dmp", "attachments.zip", "server.json"],
|
||||
},
|
||||
"limits": {
|
||||
"CRASH_SERVICE_VERSION": os.getenv("CRASH_SERVICE_VERSION", "1.0.0"),
|
||||
"CRASH_METADATA_MAX_KB": os.getenv("CRASH_METADATA_MAX_KB", "256"),
|
||||
"CRASH_MINIDUMP_MAX_MB": os.getenv("CRASH_MINIDUMP_MAX_MB", "128"),
|
||||
"CRASH_ATTACHMENTS_MAX_MB": os.getenv("CRASH_ATTACHMENTS_MAX_MB", "64"),
|
||||
"CRASH_REQUEST_MAX_MB": os.getenv("CRASH_REQUEST_MAX_MB", "200"),
|
||||
"CRASH_SYMBOLS_MAX_MB": os.getenv("CRASH_SYMBOLS_MAX_MB", "512"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def crash_report_test_text(api_base_url: str) -> str:
|
||||
values = crash_report_test_values(api_base_url)
|
||||
tokens = values["tokens"]
|
||||
lines = [
|
||||
"# 说明:下面内容仅用于后台管理员/测试人员联调崩溃报告接口。",
|
||||
"# 注意:不要复制进客户端 app_config.json,也不要放进客户端配置文件。",
|
||||
"",
|
||||
"# 服务端基础地址。curl 示例里的 SERVER 就填这个值。",
|
||||
f"SERVER_BASE_URL={values['server_base_url']}",
|
||||
"",
|
||||
"# 上传崩溃报告使用的 Token。",
|
||||
"# 用途:POST /api/v1/crash-reports",
|
||||
"# 请求头写法:Authorization: Bearer <CRASH_REPORT_TOKEN>",
|
||||
f"CRASH_REPORT_TOKEN={tokens['CRASH_REPORT_TOKEN']['token']}",
|
||||
f"CRASH_REPORT_URL={values['upload_crash_report']['url']}",
|
||||
"",
|
||||
"# 上传符号包使用的 Token。",
|
||||
"# 用途:POST /api/v1/symbols",
|
||||
"# 请求头写法:Authorization: Bearer <CRASH_SYMBOL_TOKEN>",
|
||||
f"CRASH_SYMBOL_TOKEN={tokens['CRASH_SYMBOL_TOKEN']['token']}",
|
||||
f"CRASH_SYMBOL_URL={values['upload_symbols']['url']}",
|
||||
"",
|
||||
"# 查询和下载崩溃报告使用的 Token。",
|
||||
"# 如果 CRASH_ADMIN_TOKEN 为空,就使用 ADMIN_TOKEN。",
|
||||
"# 请求头写法:Authorization: Bearer <CRASH_ADMIN_TOKEN 或 ADMIN_TOKEN>",
|
||||
f"CRASH_ADMIN_TOKEN={tokens['CRASH_ADMIN_TOKEN']['token']}",
|
||||
f"ADMIN_TOKEN={tokens['ADMIN_TOKEN']['token']}",
|
||||
f"CRASH_REPORT_DETAIL_URL_TEMPLATE={values['admin_query_and_download']['detail_url_template']}",
|
||||
f"CRASH_REPORT_FILE_URL_TEMPLATE={values['admin_query_and_download']['file_url_template']}",
|
||||
"",
|
||||
"# 可下载文件名。",
|
||||
"CRASH_REPORT_FILE_NAMES=metadata.json,crash.dmp,attachments.zip,server.json",
|
||||
"",
|
||||
"# 幂等规则:Idempotency-Key 必须等于 metadata.json 里的 clientReportId。",
|
||||
"CRASH_IDEMPOTENCY_KEY_RULE=Idempotency-Key must equal metadata.clientReportId",
|
||||
"",
|
||||
"# 崩溃报告服务版本和大小限制。",
|
||||
]
|
||||
for key, value in values["limits"].items():
|
||||
lines.append(f"{key}={value}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def normalize_executable_name(value: str) -> str:
|
||||
normalized = str(value or "").strip().replace(chr(92), "/").strip("/")
|
||||
if not normalized:
|
||||
|
||||
Reference in New Issue
Block a user