203
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# OpenInstall API 测试结果
|
||||
|
||||
## 测试总结
|
||||
|
||||
✅ **成功连接到 OpenInstall API**
|
||||
|
||||
- API 基础 URL: `https://data.openinstall.com`
|
||||
- 测试的接口端点工作正常
|
||||
- HTTP 状态码: 200
|
||||
|
||||
## 当前问题
|
||||
|
||||
❌ **ApiKey 配置错误**
|
||||
|
||||
API 返回错误: `code=3, error="apiKey错误"`
|
||||
|
||||
## 问题分析
|
||||
|
||||
当前配置中:
|
||||
- `AppKey: alf57p` - 这是应用的标识符(AppKey),用于 SDK 集成
|
||||
- 但数据接口需要的是单独的 `apiKey`,这两者不同
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 步骤 1: 在 OpenInstall 后台配置数据接口
|
||||
|
||||
1. 登录 OpenInstall 后台: https://www.openinstall.com
|
||||
2. 找到 **【数据接口】-【接口配置】** 菜单
|
||||
3. **开启数据接口开关**
|
||||
4. 获取 `apiKey` (这是专门用于数据接口的密钥,不同于 AppKey)
|
||||
|
||||
### 步骤 2: 更新配置文件
|
||||
|
||||
在 `ppanel-server/etc/ppanel.yaml` 中添加 `ApiKey`:
|
||||
|
||||
```yaml
|
||||
OpenInstall:
|
||||
Enable: true
|
||||
AppKey: "alf57p" # SDK 集成使用
|
||||
ApiKey: "your_api_key_from_backend" # 数据接口使用
|
||||
```
|
||||
|
||||
### 步骤 3: 重新测试
|
||||
|
||||
获取到正确的 apiKey 后,运行测试程序:
|
||||
|
||||
```bash
|
||||
cd cmd/test_openinstall
|
||||
go run main.go
|
||||
```
|
||||
|
||||
## 测试接口说明
|
||||
|
||||
测试程序当前测试了以下接口:
|
||||
|
||||
### 1. 新增安装数据 (Growth Data)
|
||||
- 端点: `/data/event/growth`
|
||||
- 功能: 获取指定时间范围内的访问量、点击量、安装量、注册量及留存数据
|
||||
- 参数:
|
||||
- `apiKey`: 数据接口密钥
|
||||
- `startDate`: 开始日期 (格式: 2006-01-02)
|
||||
- `endDate`: 结束日期
|
||||
- `statType`: 统计类型 (daily=按天, hourly=按小时, total=合计)
|
||||
|
||||
返回数据包括:
|
||||
- `visit`: 访问量
|
||||
- `click`: 点击量
|
||||
- `install`: 安装量
|
||||
- `register`: 注册量
|
||||
- `survive_d1`: 1日留存
|
||||
- `survive_d7`: 7日留存
|
||||
- `survive_d30`: 30日留存
|
||||
|
||||
### 2. 渠道列表 (Channel List)
|
||||
- 端点: `/data/channel/list`
|
||||
- 功能: 获取 H5 渠道列表
|
||||
- 参数:
|
||||
- `apiKey`: 数据接口密钥
|
||||
- `pageNum`: 页码
|
||||
- `pageSize`: 每页数量
|
||||
|
||||
## 更多可用接口
|
||||
|
||||
OpenInstall 数据接口还提供以下功能:
|
||||
|
||||
- 渠道分组管理 (创建、修改、删除)
|
||||
- 渠道管理 (创建、修改、删除、查询)
|
||||
- 子渠道管理
|
||||
- 存量设备数据
|
||||
- 活跃数据统计
|
||||
- 效果点数据
|
||||
- 设备分布统计
|
||||
|
||||
详细文档: https://www.openinstall.com/doc/data.html
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. **配置 ApiKey**: 按照上述步骤在 OpenInstall 后台获取并配置 apiKey
|
||||
2. **更新配置**: 将 apiKey 添加到 `ppanel.yaml` 配置文件
|
||||
3. **更新代码**: 修改 `pkg/openinstall/openinstall.go` 实现真实的 API 调用
|
||||
4. **测试验证**: 重新运行测试程序验证数据获取
|
||||
@@ -0,0 +1,254 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// OpenInstall 数据接口基础 URL
|
||||
apiBaseURL = "https://data.openinstall.com"
|
||||
|
||||
// 您的 ApiKey (数据接口密钥)
|
||||
apiKey = "a7596bc007f31a98ca551e33a75d3bb5997b0b94027c6e988d3c0af1"
|
||||
)
|
||||
|
||||
// 通用响应结构
|
||||
type APIResponse struct {
|
||||
Code int `json:"code"`
|
||||
Error *string `json:"error"`
|
||||
Body json.RawMessage `json:"body"`
|
||||
}
|
||||
|
||||
// 新增安装数据
|
||||
type GrowthData struct {
|
||||
Date string `json:"date"`
|
||||
Visit int64 `json:"visit"` // 点击量
|
||||
Click int64 `json:"click"` // 访问量
|
||||
Install int64 `json:"install"` // 安装量
|
||||
Register int64 `json:"register"` // 注册量
|
||||
SurviveD1 int64 `json:"survive_d1"` // 1日留存
|
||||
SurviveD7 int64 `json:"survive_d7"` // 7日留存
|
||||
SurviveD30 int64 `json:"survive_d30"` // 30日留存
|
||||
}
|
||||
|
||||
// 渠道列表数据
|
||||
type ChannelData struct {
|
||||
ChannelCode string `json:"channelCode"`
|
||||
ChannelName string `json:"channelName"`
|
||||
LinkURL string `json:"linkUrl"`
|
||||
CreateTime string `json:"createTime"`
|
||||
GroupName string `json:"groupName"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("========================================")
|
||||
fmt.Println("OpenInstall API 测试程序")
|
||||
fmt.Println("========================================")
|
||||
fmt.Printf("ApiKey: %s\n", apiKey)
|
||||
fmt.Printf("API Base URL: %s\n", apiBaseURL)
|
||||
fmt.Println()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 测试1: 获取新增安装数据(最近7天)
|
||||
fmt.Println("测试1: 获取新增安装数据(最近7天)")
|
||||
fmt.Println("========================================")
|
||||
testGrowthData(ctx, 7)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 测试2: 获取新增安装数据(最近30天)
|
||||
fmt.Println("测试2: 获取新增安装数据(最近30天)")
|
||||
fmt.Println("========================================")
|
||||
testGrowthData(ctx, 30)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 测试3: 获取渠道列表
|
||||
fmt.Println("测试3: 获取渠道列表")
|
||||
fmt.Println("========================================")
|
||||
testChannelList(ctx)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("========================================")
|
||||
fmt.Println("测试完成!")
|
||||
fmt.Println("========================================")
|
||||
}
|
||||
|
||||
// 测试获取新增安装数据
|
||||
func testGrowthData(ctx context.Context, days int) {
|
||||
// 设置查询时间范围
|
||||
endDate := time.Now()
|
||||
startDate := endDate.AddDate(0, 0, -days)
|
||||
|
||||
// 构建 API URL
|
||||
apiURL := fmt.Sprintf("%s/data/event/growth", apiBaseURL)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("apiKey", apiKey)
|
||||
params.Add("startDate", startDate.Format("2006-01-02"))
|
||||
params.Add("endDate", endDate.Format("2006-01-02"))
|
||||
params.Add("statType", "daily") // daily = 按天统计, hourly = 按小时统计, total = 合计
|
||||
|
||||
fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode())
|
||||
fmt.Printf("请求 URL: %s\n", fullURL)
|
||||
|
||||
body, statusCode, err := makeRequest(ctx, fullURL)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 请求失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("HTTP 状态码: %d\n", statusCode)
|
||||
|
||||
if statusCode == 200 {
|
||||
// 解析响应
|
||||
var apiResp APIResponse
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
fmt.Printf("❌ JSON 解析失败: %v\n", err)
|
||||
printRawResponse(body)
|
||||
return
|
||||
}
|
||||
|
||||
if apiResp.Code == 0 {
|
||||
fmt.Println("✅ 成功获取数据!")
|
||||
|
||||
// 解析业务数据
|
||||
var growthData []GrowthData
|
||||
if err := json.Unmarshal(apiResp.Body, &growthData); err != nil {
|
||||
fmt.Printf("⚠️ 业务数据解析失败: %v\n", err)
|
||||
printRawResponse(body)
|
||||
return
|
||||
}
|
||||
|
||||
// 格式化输出数据
|
||||
fmt.Printf("\n共获取 %d 天的数据:\n", len(growthData))
|
||||
fmt.Println("----------------------------------------")
|
||||
for _, data := range growthData {
|
||||
fmt.Printf("日期: %s\n", data.Date)
|
||||
fmt.Printf(" 访问量(visit): %d\n", data.Visit)
|
||||
fmt.Printf(" 点击量(click): %d\n", data.Click)
|
||||
fmt.Printf(" 安装量(install): %d\n", data.Install)
|
||||
fmt.Printf(" 注册量(register): %d\n", data.Register)
|
||||
fmt.Printf(" 1日留存: %d\n", data.SurviveD1)
|
||||
fmt.Printf(" 7日留存: %d\n", data.SurviveD7)
|
||||
fmt.Printf(" 30日留存: %d\n", data.SurviveD30)
|
||||
fmt.Println("----------------------------------------")
|
||||
}
|
||||
} else {
|
||||
errMsg := "未知错误"
|
||||
if apiResp.Error != nil {
|
||||
errMsg = *apiResp.Error
|
||||
}
|
||||
fmt.Printf("❌ API 返回错误 (code=%d): %s\n", apiResp.Code, errMsg)
|
||||
printRawResponse(body)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("❌ HTTP 请求失败\n")
|
||||
printRawResponse(body)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取渠道列表
|
||||
func testChannelList(ctx context.Context) {
|
||||
// 构建 API URL
|
||||
apiURL := fmt.Sprintf("%s/data/channel/list", apiBaseURL)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("apiKey", apiKey)
|
||||
params.Add("pageNum", "0")
|
||||
params.Add("pageSize", "20")
|
||||
|
||||
fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode())
|
||||
fmt.Printf("请求 URL: %s\n", fullURL)
|
||||
|
||||
body, statusCode, err := makeRequest(ctx, fullURL)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 请求失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("HTTP 状态码: %d\n", statusCode)
|
||||
|
||||
if statusCode == 200 {
|
||||
// 解析响应
|
||||
var apiResp APIResponse
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
fmt.Printf("❌ JSON 解析失败: %v\n", err)
|
||||
printRawResponse(body)
|
||||
return
|
||||
}
|
||||
|
||||
if apiResp.Code == 0 {
|
||||
fmt.Println("✅ 成功获取渠道列表!")
|
||||
|
||||
// 直接打印原始数据
|
||||
printJSONResponse(apiResp.Body)
|
||||
} else {
|
||||
errMsg := "未知错误"
|
||||
if apiResp.Error != nil {
|
||||
errMsg = *apiResp.Error
|
||||
}
|
||||
fmt.Printf("❌ API 返回错误 (code=%d): %s\n", apiResp.Code, errMsg)
|
||||
printRawResponse(body)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("❌ HTTP 请求失败\n")
|
||||
printRawResponse(body)
|
||||
}
|
||||
}
|
||||
|
||||
// 发送 HTTP 请求
|
||||
func makeRequest(ctx context.Context, url string) ([]byte, int, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("创建请求失败: %w", err)
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("发送请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, resp.StatusCode, fmt.Errorf("读取响应失败: %w", err)
|
||||
}
|
||||
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
// 打印原始响应
|
||||
func printRawResponse(body []byte) {
|
||||
fmt.Println("\n原始响应内容:")
|
||||
var prettyJSON map[string]interface{}
|
||||
if err := json.Unmarshal(body, &prettyJSON); err == nil {
|
||||
formatted, _ := json.MarshalIndent(prettyJSON, "", " ")
|
||||
fmt.Println(string(formatted))
|
||||
} else {
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
}
|
||||
|
||||
// 打印 JSON 响应
|
||||
func printJSONResponse(data json.RawMessage) {
|
||||
var prettyJSON interface{}
|
||||
if err := json.Unmarshal(data, &prettyJSON); err == nil {
|
||||
formatted, _ := json.MarshalIndent(prettyJSON, "", " ")
|
||||
fmt.Println(string(formatted))
|
||||
} else {
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user