255 lines
6.8 KiB
Go
255 lines
6.8 KiB
Go
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))
|
||
}
|
||
}
|