feat: 增加详细日志, 覆盖所有接口和核心业务逻辑

This commit is contained in:
ShenQiLun 2026-06-26 16:23:44 +08:00
parent 2c90c95b55
commit 05bec7f1d0
8 changed files with 197 additions and 42 deletions

View File

@ -3,6 +3,7 @@ package database
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"log"
"os" "os"
_ "modernc.org/sqlite" _ "modernc.org/sqlite"
@ -14,9 +15,12 @@ var DB *sql.DB
func InitDB(dbPath string) error { func InitDB(dbPath string) error {
var err error var err error
log.Printf("[DB] 初始化数据库: path=%s", dbPath)
// 确保数据库目录存在 // 确保数据库目录存在
dir := "./data" dir := "./data"
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {
log.Printf("[DB] 数据库目录不存在, 创建: %s", dir)
os.MkdirAll(dir, 0755) os.MkdirAll(dir, 0755)
} }
@ -32,6 +36,7 @@ func InitDB(dbPath string) error {
return fmt.Errorf("创建表失败: %w", err) return fmt.Errorf("创建表失败: %w", err)
} }
log.Printf("[DB] 数据库初始化完成")
return nil return nil
} }

View File

@ -28,13 +28,19 @@ func NewConfigHandler(configPath string) *ConfigHandler {
// GetConfigPrice 获取配置 // GetConfigPrice 获取配置
// 先读 yamlPort/TimerInterval/APIRateLimit/CallbackURL再用数据库值覆盖价格字段 // 先读 yamlPort/TimerInterval/APIRateLimit/CallbackURL再用数据库值覆盖价格字段
func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) { func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[GetConfigPrice] 收到请求, 来源IP: %s", clientIP)
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
// 1. 加载yaml配置 // 1. 加载yaml配置
cfg, err := config.Load(h.configPath) cfg, err := config.Load(h.configPath)
if err != nil { if err != nil {
log.Printf("[GetConfigPrice] 读取配置失败: %s", err.Error()) log.Printf("[GetConfigPrice] 读取配置失败: %s, 来源IP: %s", err.Error(), clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"读取配置失败: %s"}`, err.Error()))) w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"读取配置失败: %s"}`, err.Error())))
return return
@ -56,6 +62,9 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
// 同步全局配置 // 同步全局配置
config.SetGlobal(cfg) config.SetGlobal(cfg)
log.Printf("[GetConfigPrice] 返回配置: port=%s, new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
cfg.Port, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{ json.NewEncoder(w).Encode(map[string]interface{}{
"code": 200, "code": 200,
@ -70,6 +79,12 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
func (h *ConfigHandler) SetConfigPrice(w http.ResponseWriter, r *http.Request) { func (h *ConfigHandler) SetConfigPrice(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20) r.ParseMultipartForm(32 << 20)
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[SetConfigPrice] 收到请求, 来源IP: %s", clientIP)
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()

View File

@ -25,8 +25,15 @@ func NewGoodsHandler(goodsService *service.GoodsService) *GoodsHandler {
// QueryGoods 查询商品接口 // QueryGoods 查询商品接口
func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) { func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[QueryGoods] 收到请求, 来源IP: %s, Method: %s", clientIP, r.Method)
// 只支持POST请求 // 只支持POST请求
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
log.Printf("[QueryGoods] 方法不允许: %s, 来源IP: %s", r.Method, clientIP)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return return
} }
@ -34,8 +41,7 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
// 读取原始body用于调试 // 读取原始body用于调试
bodyBytes, _ := io.ReadAll(r.Body) bodyBytes, _ := io.ReadAll(r.Body)
bodyStr := string(bodyBytes) bodyStr := string(bodyBytes)
log.Printf("收到原始请求 Body: [%s]", bodyStr) log.Printf("[QueryGoods] 原始请求 Body: [%s], Content-Type: [%s]", bodyStr, r.Header.Get("Content-Type"))
log.Printf("Content-Type: [%s]", r.Header.Get("Content-Type"))
// 重新创建body供ParseForm使用 // 重新创建body供ParseForm使用
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
@ -44,33 +50,43 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(32 << 20); err != nil { if err := r.ParseMultipartForm(32 << 20); err != nil {
// 尝试纯表单解析 // 尝试纯表单解析
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
log.Printf("ParseForm 失败: %v", err) log.Printf("[QueryGoods] 参数解析失败: %v, 来源IP: %s", err, clientIP)
http.Error(w, "Invalid request form", http.StatusBadRequest) http.Error(w, "Invalid request form", http.StatusBadRequest)
return return
} }
} }
// 调试日志 isbn := r.FormValue("isbn")
log.Printf("解析结果 - isbn: [%s], book_name: [%s], author: [%s], publishing: [%s], out_id: [%s], quality: [%s], query_index: [%s], user_id: [%s], placeholder_down_price: [%s], min_shipping_fee: [%s], min_price: [%s] ", bookName := r.FormValue("book_name")
r.FormValue("isbn"), r.FormValue("book_name"), r.FormValue("author"), r.FormValue("publishing"), author := r.FormValue("author")
r.FormValue("out_id"), r.FormValue("quality"), publishing := r.FormValue("publishing")
r.FormValue("query_index"), r.FormValue("user_id"), r.FormValue("placeholder_down_price"), r.FormValue("min_shipping_fee"), r.FormValue("min_price")) outID := r.FormValue("out_id")
quality := r.FormValue("quality")
queryIndex := r.FormValue("query_index")
userID := r.FormValue("user_id")
placeholderDownPrice := r.FormValue("placeholder_down_price")
minShippingFee := r.FormValue("min_shipping_fee")
minPrice := r.FormValue("min_price")
log.Printf("[QueryGoods] 解析参数完成 - isbn=[%s], book_name=[%s], author=[%s], publishing=[%s], out_id=[%s], quality=[%s], query_index=[%s], user_id=[%s], placeholder_down_price=[%s], min_shipping_fee=[%s], min_price=[%s]",
isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice)
var req service.QueryRequest var req service.QueryRequest
req.ISBN = r.FormValue("isbn") req.ISBN = isbn
req.BookName = r.FormValue("book_name") req.BookName = bookName
req.Author = r.FormValue("author") req.Author = author
req.Publishing = r.FormValue("publishing") req.Publishing = publishing
req.OutID = r.FormValue("out_id") req.OutID = outID
req.Quality = r.FormValue("quality") req.Quality = quality
req.QueryIndex, _ = strconv.Atoi(r.FormValue("query_index")) req.QueryIndex, _ = strconv.Atoi(queryIndex)
req.UserID = r.FormValue("user_id") req.UserID = userID
req.PlaceholderDownPrice, _ = strconv.ParseFloat(r.FormValue("placeholder_down_price"), 64) req.PlaceholderDownPrice, _ = strconv.ParseFloat(placeholderDownPrice, 64)
req.MinShippingFee, _ = strconv.ParseFloat(r.FormValue("min_shipping_fee"), 64) req.MinShippingFee, _ = strconv.ParseFloat(minShippingFee, 64)
req.MinPrice, _ = strconv.ParseFloat(r.FormValue("min_price"), 64) req.MinPrice, _ = strconv.ParseFloat(minPrice, 64)
// 调用服务层 // 调用服务层
resp := h.goodsService.QueryGoods(&req) resp := h.goodsService.QueryGoods(&req)
log.Printf("[QueryGoods] 处理完成, ID=%d, Code=%d, Message=%s", resp.ID, resp.Code, resp.Message)
// 返回响应 // 返回响应
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@ -3,10 +3,12 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/parnurzeal/gorequest" "log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
"github.com/parnurzeal/gorequest"
) )
// KfzHandler Kfz处理器 // KfzHandler Kfz处理器
@ -20,31 +22,43 @@ func NewKfzHandler() *KfzHandler {
// KfzLogin 登录孔网并返回用户信息 // KfzLogin 登录孔网并返回用户信息
func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) { func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[KfzLogin] 收到登录请求, 来源IP: %s", clientIP)
r.ParseMultipartForm(32 << 20) r.ParseMultipartForm(32 << 20)
username := r.PostForm.Get("username") username := r.PostForm.Get("username")
password := r.PostForm.Get("password") password := r.PostForm.Get("password")
if username == "" || password == "" { if username == "" || password == "" {
log.Printf("[KfzLogin] username或password为空, 来源IP: %s", clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"code":500,"message":"username和password不能为空"}`)) w.Write([]byte(`{"code":500,"message":"username和password不能为空"}`))
return return
} }
log.Printf("[KfzLogin] 开始登录孔网, username=%s, 来源IP: %s", username, clientIP)
token, err := outKfzLogin(username, password) token, err := outKfzLogin(username, password)
if err != nil { if err != nil {
log.Printf("[KfzLogin] 孔网登录失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error()))) w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
return return
} }
log.Printf("[KfzLogin] 孔网登录成功: username=%s, token=%s..., 来源IP: %s", username, token[:min(len(token), 10)], clientIP)
userInfo, err := outKfzGetUserInfo(token) userInfo, err := outKfzGetUserInfo(token)
if err != nil { if err != nil {
log.Printf("[KfzLogin] 获取用户信息失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error()))) w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
return return
} }
userInfo.Token = token userInfo.Token = token
log.Printf("[KfzLogin] 登录成功: username=%s, userId=%d, nickname=%s, 来源IP: %s", username, userInfo.UserID, userInfo.Nickname, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{ json.NewEncoder(w).Encode(map[string]interface{}{
@ -54,6 +68,13 @@ func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
}) })
} }
func min(a, b int) int {
if a < b {
return a
}
return b
}
/* /*
* 孔网登录 * 孔网登录
* param username[string] 孔网用户名 * param username[string] 孔网用户名

View File

@ -36,22 +36,27 @@ type TokenInput struct {
// BatchAddTokens 批量添加TokenJSON数组: [{"username":"","token":""},...] // BatchAddTokens 批量添加TokenJSON数组: [{"username":"","token":""},...]
func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) { func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return return
} }
var inputs []TokenInput var inputs []TokenInput
if err := json.NewDecoder(r.Body).Decode(&inputs); err != nil { if err := json.NewDecoder(r.Body).Decode(&inputs); err != nil {
log.Printf("BatchAddTokens - decode error: %v", err) log.Printf("[Token/BatchAdd] 请求体解析失败: %v, 来源IP: %s", err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "invalid request body"}) json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "invalid request body"})
return return
} }
log.Printf("BatchAddTokens - received %d tokens", len(inputs)) log.Printf("[Token/BatchAdd] 收到请求, 来源IP: %s, token数量: %d", clientIP, len(inputs))
if len(inputs) == 0 { if len(inputs) == 0 {
log.Printf("[Token/BatchAdd] 空数组, 来源IP: %s", clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "empty array"}) json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "empty array"})
return return
@ -59,21 +64,25 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
// 逐条插入 // 逐条插入
var failed []TokenInput var failed []TokenInput
for _, input := range inputs { for i, input := range inputs {
if input.Username == "" || input.Token == "" { if input.Username == "" || input.Token == "" {
log.Printf("[Token/BatchAdd] 第%d条数据不完整(username或token为空), 跳过", i+1)
failed = append(failed, input) failed = append(failed, input)
continue continue
} }
_, err := h.tokenRepo.Insert(input.Username, input.Token, true) id, err := h.tokenRepo.Insert(input.Username, input.Token, true)
if err != nil { if err != nil {
log.Printf("BatchAddTokens - insert error: %v", err) log.Printf("[Token/BatchAdd] 第%d条插入失败: username=%s, 错误=%v", i+1, input.Username, err)
failed = append(failed, input) failed = append(failed, input)
} else {
log.Printf("[Token/BatchAdd] 第%d条插入成功: id=%d, username=%s", i+1, id, input.Username)
} }
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if len(failed) > 0 { if len(failed) > 0 {
log.Printf("[Token/BatchAdd] 部分成功: 成功%d条, 失败%d条, 来源IP: %s", len(inputs)-len(failed), len(failed), clientIP)
json.NewEncoder(w).Encode(TokenResponse{ json.NewEncoder(w).Encode(TokenResponse{
Code: 207, Code: 207,
Message: "partial success", Message: "partial success",
@ -82,31 +91,44 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
return return
} }
log.Printf("[Token/BatchAdd] 全部成功: %d条, 来源IP: %s", len(inputs), clientIP)
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
} }
// GetAllTokens 查询所有Token // GetAllTokens 查询所有Token
func (h *TokenHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) { func (h *TokenHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[Token/GetAll] 收到请求, 来源IP: %s", clientIP)
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return return
} }
records, err := h.tokenRepo.GetAll() records, err := h.tokenRepo.GetAll()
if err != nil { if err != nil {
log.Printf("[Token/GetAll] 查询失败: %v, 来源IP: %s", err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
return return
} }
log.Printf("[Token/GetAll] 查询成功: 共%d条记录, 来源IP: %s", len(records), clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records}) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
} }
// DeleteToken 删除Token // DeleteToken 删除Token
func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) { func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[Token/Delete] 收到请求, 来源IP: %s", clientIP)
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return return
} }
@ -122,25 +144,33 @@ func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(idStr, 10, 64) id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil { if err != nil {
log.Printf("[Token/Delete] 参数id无效: %s, 来源IP: %s", idStr, clientIP)
http.Error(w, "invalid id", http.StatusBadRequest) http.Error(w, "invalid id", http.StatusBadRequest)
return return
} }
err = h.tokenRepo.Delete(id) err = h.tokenRepo.Delete(id)
if err != nil { if err != nil {
log.Printf("[Token/Delete] 删除失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
return return
} }
log.Printf("[Token/Delete] 删除成功: id=%d, 来源IP: %s", id, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
} }
// UpdateToken 修改Token // UpdateToken 修改Token
func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) { func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[Token/Update] 收到请求, 来源IP: %s", clientIP)
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return return
} }
@ -155,6 +185,7 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(idStr, 10, 64) id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil { if err != nil {
log.Printf("[Token/Update] 参数id无效: %s, 来源IP: %s", idStr, clientIP)
http.Error(w, "invalid id", http.StatusBadRequest) http.Error(w, "invalid id", http.StatusBadRequest)
return return
} }
@ -164,31 +195,41 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
isEnable = false isEnable = false
} }
log.Printf("[Token/Update] 更新: id=%d, username=%s, is_enable=%v, 来源IP: %s", id, username, isEnable, clientIP)
err = h.tokenRepo.Update(id, username, token, isEnable) err = h.tokenRepo.Update(id, username, token, isEnable)
if err != nil { if err != nil {
log.Printf("[Token/Update] 更新失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
return return
} }
log.Printf("[Token/Update] 更新成功: id=%d, 来源IP: %s", id, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
} }
// GetEnabledTokens 获取所有启用的Token // GetEnabledTokens 获取所有启用的Token
func (h *TokenHandler) GetEnabledTokens(w http.ResponseWriter, r *http.Request) { func (h *TokenHandler) GetEnabledTokens(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
clientIP = forwarded
}
log.Printf("[Token/GetEnabled] 收到请求, 来源IP: %s", clientIP)
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return return
} }
records, err := h.tokenRepo.GetEnabledTokens() records, err := h.tokenRepo.GetEnabledTokens()
if err != nil { if err != nil {
log.Printf("[Token/GetEnabled] 查询失败: %v, 来源IP: %s", err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
return return
} }
log.Printf("[Token/GetEnabled] 查询成功: 共%d条启用token, 来源IP: %s", len(records), clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records}) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
} }

View File

@ -3,6 +3,7 @@ package repository
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"log"
"kfz-goods-pricing/internal/database" "kfz-goods-pricing/internal/database"
) )
@ -26,11 +27,15 @@ func GetKfzConfig() (*KfzConfig, error) {
).Scan(&cfg.ID, &cfg.NewPrice, &cfg.PlaceholderDownPrice, &cfg.MinShippingFee, &cfg.MinPrice, &cfg.QueryIndex) ).Scan(&cfg.ID, &cfg.NewPrice, &cfg.PlaceholderDownPrice, &cfg.MinShippingFee, &cfg.MinPrice, &cfg.QueryIndex)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Printf("[Repo/Config] kfz_config表无数据")
return nil, nil // 无数据 return nil, nil // 无数据
} }
if err != nil { if err != nil {
log.Printf("[Repo/Config] 查询kfz_config失败: %v", err)
return nil, fmt.Errorf("查询kfz_config失败: %w", err) return nil, fmt.Errorf("查询kfz_config失败: %w", err)
} }
log.Printf("[Repo/Config] 查询成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
return &cfg, nil return &cfg, nil
} }
@ -40,6 +45,7 @@ func SaveKfzConfig(cfg *KfzConfig) error {
var count int var count int
err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_config").Scan(&count) err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_config").Scan(&count)
if err != nil { if err != nil {
log.Printf("[Repo/Config] 查询kfz_config数量失败: %v", err)
return fmt.Errorf("查询kfz_config失败: %w", err) return fmt.Errorf("查询kfz_config失败: %w", err)
} }
@ -49,16 +55,22 @@ func SaveKfzConfig(cfg *KfzConfig) error {
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
) )
if err != nil { if err != nil {
log.Printf("[Repo/Config] 插入配置失败: %v", err)
return fmt.Errorf("插入kfz_config失败: %w", err) return fmt.Errorf("插入kfz_config失败: %w", err)
} }
log.Printf("[Repo/Config] 插入配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
} else { } else {
_, err = database.DB.Exec( _, err = database.DB.Exec(
`UPDATE kfz_config SET new_price=?, placeholder_down_price=?, min_shipping_fee=?, min_price=?, query_index=? WHERE id=1`, `UPDATE kfz_config SET new_price=?, placeholder_down_price=?, min_shipping_fee=?, min_price=?, query_index=? WHERE id=1`,
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
) )
if err != nil { if err != nil {
log.Printf("[Repo/Config] 更新配置失败: %v", err)
return fmt.Errorf("更新kfz_config失败: %w", err) return fmt.Errorf("更新kfz_config失败: %w", err)
} }
log.Printf("[Repo/Config] 更新配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
} }
return nil return nil
} }

View File

@ -3,6 +3,7 @@ package repository
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"log"
"kfz-goods-pricing/internal/database" "kfz-goods-pricing/internal/database"
) )
@ -40,14 +41,17 @@ func (r *GoodsRepository) Insert(isbn, bookName, author, publishing, outID, qual
result, err := database.DB.Exec(query, isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice) result, err := database.DB.Exec(query, isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice)
if err != nil { if err != nil {
log.Printf("[Repo/Goods] 插入记录失败: isbn=%s, out_id=%s, 错误=%v", isbn, outID, err)
return 0, fmt.Errorf("插入记录失败: %w", err) return 0, fmt.Errorf("插入记录失败: %w", err)
} }
id, err := result.LastInsertId() id, err := result.LastInsertId()
if err != nil { if err != nil {
log.Printf("[Repo/Goods] 获取自增ID失败: %v", err)
return 0, fmt.Errorf("获取自增ID失败: %w", err) return 0, fmt.Errorf("获取自增ID失败: %w", err)
} }
log.Printf("[Repo/Goods] 插入成功: id=%d, isbn=%s, out_id=%s, min_price=%.2f", id, isbn, outID, minPrice)
return id, nil return id, nil
} }
@ -57,16 +61,23 @@ func (r *GoodsRepository) UpdatePrice(id int64, price, shippingFee, finalPrice f
_, err := database.DB.Exec(query, price, shippingFee, finalPrice, id) _, err := database.DB.Exec(query, price, shippingFee, finalPrice, id)
if err != nil { if err != nil {
log.Printf("[Repo/Goods] 更新价格失败: id=%d, 错误=%v", id, err)
return fmt.Errorf("更新价格失败: %w", err) return fmt.Errorf("更新价格失败: %w", err)
} }
log.Printf("[Repo/Goods] 更新价格成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", id, price, shippingFee, finalPrice)
return nil return nil
} }
// MarkFailed 标记查询失败fail_count+1更新updated_at // MarkFailed 标记查询失败fail_count+1更新updated_at
func (r *GoodsRepository) MarkFailed(id int64) { func (r *GoodsRepository) MarkFailed(id int64) {
query := `UPDATE goods_pricing SET fail_count = fail_count + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?` query := `UPDATE goods_pricing SET fail_count = fail_count + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
database.DB.Exec(query, id) _, err := database.DB.Exec(query, id)
if err != nil {
log.Printf("[Repo/Goods] 标记失败: id=%d, 错误=%v", id, err)
} else {
log.Printf("[Repo/Goods] 标记失败成功: id=%d", id)
}
} }
// GetByID 根据ID查询记录 // GetByID 根据ID查询记录
@ -144,6 +155,7 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} }
log.Printf("[Repo/Goods] 查询待处理记录失败: %v", err)
return nil, fmt.Errorf("查询记录失败: %w", err) return nil, fmt.Errorf("查询记录失败: %w", err)
} }
@ -166,5 +178,6 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) {
record.MinPrice = minPrice.Float64 record.MinPrice = minPrice.Float64
} }
log.Printf("[Repo/Goods] 查询到待处理记录: id=%d, isbn=%s, book_name=%s, fail_count=%d", record.ID, record.ISBN, record.BookName, record.FailCount)
return &record, nil return &record, nil
} }

View File

@ -67,6 +67,7 @@ type QueryResponse struct {
// QueryGoods 查询商品信息 // QueryGoods 查询商品信息
func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse { func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse {
if req.ISBN == "0" { if req.ISBN == "0" {
log.Printf("[QueryGoods] ISBN为0, 跳过处理")
return &QueryResponse{ return &QueryResponse{
Code: 200, Code: 200,
Message: "success", Message: "success",
@ -76,12 +77,15 @@ func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse {
// 插入入参记录到数据库 // 插入入参记录到数据库
id, err := s.goodsRepository.Insert(req.ISBN, req.BookName, req.Author, req.Publishing, req.OutID, req.Quality, req.UserID, req.QueryIndex, req.PlaceholderDownPrice, req.MinShippingFee, req.MinPrice) id, err := s.goodsRepository.Insert(req.ISBN, req.BookName, req.Author, req.Publishing, req.OutID, req.Quality, req.UserID, req.QueryIndex, req.PlaceholderDownPrice, req.MinShippingFee, req.MinPrice)
if err != nil { if err != nil {
log.Printf("[QueryGoods] 保存记录失败: isbn=%s, out_id=%s, user_id=%s, 错误=%v", req.ISBN, req.OutID, req.UserID, err)
return &QueryResponse{ return &QueryResponse{
Code: 500, Code: 500,
Message: fmt.Sprintf("保存记录失败: %v", err), Message: fmt.Sprintf("保存记录失败: %v", err),
} }
} }
log.Printf("[QueryGoods] 记录保存成功: id=%d, isbn=%s, book_name=%s, out_id=%s, user_id=%s", id, req.ISBN, req.BookName, req.OutID, req.UserID)
return &QueryResponse{ return &QueryResponse{
Code: 200, Code: 200,
Message: "success", Message: "success",
@ -135,6 +139,7 @@ func (s *GoodsService) sendCallback(outID, userID string, price, shippingFee flo
// StartTimerScheduler 启动定时器 // StartTimerScheduler 启动定时器
func (s *GoodsService) StartTimerScheduler(intervalSeconds int) { func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
log.Printf("[TimerScheduler] 定时器启动, 间隔=%d秒", intervalSeconds)
ticker := time.NewTicker(time.Duration(intervalSeconds) * time.Second) ticker := time.NewTicker(time.Duration(intervalSeconds) * time.Second)
go func() { go func() {
for range ticker.C { for range ticker.C {
@ -145,23 +150,29 @@ func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
// syncGoodsPricing 定时同步商品价格 // syncGoodsPricing 定时同步商品价格
func (s *GoodsService) syncGoodsPricing() { func (s *GoodsService) syncGoodsPricing() {
//cfg := config.GetGlobal() log.Printf("[syncGoodsPricing] ===== 开始执行定时同步任务 =====")
// 查询数据库数据 // 查询数据库数据
kfzConfig, err := repository.GetKfzConfig() kfzConfig, err := repository.GetKfzConfig()
if err != nil { if err != nil {
log.Printf("获取config数据库数据失败: %v", err) log.Printf("[syncGoodsPricing] 获取config数据库数据失败: %v", err)
return return
} }
log.Printf("[syncGoodsPricing] 全局配置: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
kfzConfig.NewPrice, kfzConfig.PlaceholderDownPrice, kfzConfig.MinShippingFee, kfzConfig.MinPrice, kfzConfig.QueryIndex)
// 查询一条记录按fail_count升序、updated_at倒序 // 查询一条记录按fail_count升序、updated_at倒序
record, err := s.goodsRepository.GetAllOrderByUpdatedAt() record, err := s.goodsRepository.GetAllOrderByUpdatedAt()
if err != nil { if err != nil {
log.Printf("定时任务查询失败: %v", err) log.Printf("[syncGoodsPricing] 查询待处理记录失败: %v", err)
return return
} }
if record == nil { if record == nil {
log.Printf("[syncGoodsPricing] 没有待处理的记录, 跳过本次同步")
return return
} }
log.Printf("[syncGoodsPricing] 获取到待处理记录: id=%d, isbn=%s, book_name=%s, out_id=%s, fail_count=%d",
record.ID, record.ISBN, record.BookName, record.OutID, record.FailCount)
// 限流等待 // 限流等待
s.rateLimitWait() s.rateLimitWait()
@ -172,33 +183,45 @@ func (s *GoodsService) syncGoodsPricing() {
var finalPrice float64 var finalPrice float64
// 查询孔网数据 // 查询孔网数据
log.Printf("[syncGoodsPricing] 开始查询孔网数据: id=%d, isbn=%s, book_name=%s", record.ID, record.ISBN, record.BookName)
bookInfo, err := s.outGetAllGoods(record.ISBN, record.BookName, record.Author, record.Publishing, record.Quality, record.QueryIndex) bookInfo, err := s.outGetAllGoods(record.ISBN, record.BookName, record.Author, record.Publishing, record.Quality, record.QueryIndex)
if err != nil { if err != nil {
log.Printf("[syncGoodsPricing] 查询孔网失败: id=%d, 错误=%v", record.ID, err)
if kfzConfig.NewPrice == 0 { if kfzConfig.NewPrice == 0 {
s.goodsRepository.MarkFailed(record.ID) s.goodsRepository.MarkFailed(record.ID)
log.Printf("定时任务[%d]查询孔网失败(fail_count=%d): %v", record.ID, record.FailCount+1, err) log.Printf("[syncGoodsPricing] 标记失败: id=%d, fail_count=%d, new_price=0不启用兜底", record.ID, record.FailCount+1)
return return
} }
finalPrice = kfzConfig.NewPrice finalPrice = kfzConfig.NewPrice
log.Printf("[syncGoodsPricing] 查询失败, 启用兜底价格: finalPrice=%.2f (new_price)", finalPrice)
} else { } else {
// 查询成功,更新价格 // 查询成功,更新价格
price, _ = strconv.ParseFloat(bookInfo.Price, 64) price, _ = strconv.ParseFloat(bookInfo.Price, 64)
shippingFee, _ = strconv.ParseFloat(bookInfo.ShippingFee, 64) shippingFee, _ = strconv.ParseFloat(bookInfo.ShippingFee, 64)
totalPrice := price + shippingFee totalPrice := price + shippingFee
log.Printf("[syncGoodsPricing] 孔网数据: id=%d, price=%.2f, shipping_fee=%.2f, total=%.2f", record.ID, price, shippingFee, totalPrice)
log.Printf("[syncGoodsPricing] 计算参数: placeholder_down_price=%.2f, min_shipping_fee=%.2f, kfzConfig.min_price=%.2f",
record.PlaceholderDownPrice, record.MinShippingFee, kfzConfig.MinPrice)
finalPrice = totalPrice - record.PlaceholderDownPrice - record.MinShippingFee finalPrice = totalPrice - record.PlaceholderDownPrice - record.MinShippingFee
log.Printf("[syncGoodsPricing] 减去占位降价和运费后: finalPrice=%.2f", finalPrice)
if finalPrice < kfzConfig.MinPrice { if finalPrice < kfzConfig.MinPrice {
log.Printf("[syncGoodsPricing] 价格低于最低书价, 使用最低书价: %.2f -> %.2f", finalPrice, kfzConfig.MinPrice)
finalPrice = kfzConfig.MinPrice finalPrice = kfzConfig.MinPrice
} }
// 保留两位小数 // 保留两位小数
beforeRound := finalPrice
finalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", finalPrice), 64) finalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", finalPrice), 64)
log.Printf("[syncGoodsPricing] 最终价格取两位小数: %.2f -> %.2f", beforeRound, finalPrice)
} }
if err := s.goodsRepository.UpdatePrice(record.ID, price, shippingFee, finalPrice); err != nil { if err := s.goodsRepository.UpdatePrice(record.ID, price, shippingFee, finalPrice); err != nil {
log.Printf("定时任务[%d]更新价格失败: %v", record.ID, err) log.Printf("[syncGoodsPricing] 更新价格失败: id=%d, 错误=%v", record.ID, err)
return return
} }
log.Printf("定时任务[%d]更新成功: price=%.2f, shipping_fee=%.2f", record.ID, price, shippingFee) log.Printf("[syncGoodsPricing] 更新成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", record.ID, price, shippingFee, finalPrice)
// 调用回调 // 调用回调
s.sendCallback(record.OutID, record.UserID, finalPrice, record.MinShippingFee, kfzConfig.MinPrice) s.sendCallback(record.OutID, record.UserID, finalPrice, record.MinShippingFee, kfzConfig.MinPrice)
@ -211,8 +234,10 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
// 从数据库获取启用的token列表 // 从数据库获取启用的token列表
tokens, err := s.tokenRepository.GetEnabledTokens() tokens, err := s.tokenRepository.GetEnabledTokens()
if err != nil || len(tokens) == 0 { if err != nil || len(tokens) == 0 {
log.Printf("[outGetAllGoods] 没有可用的token, 查询终止")
return nil, fmt.Errorf("没有可用的token") return nil, fmt.Errorf("没有可用的token")
} }
log.Printf("[outGetAllGoods] 可用token数量: %d", len(tokens))
// 轮询选择token // 轮询选择token
s.tokenMu.Lock() s.tokenMu.Lock()
@ -222,8 +247,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
s.tokenMu.Unlock() s.tokenMu.Unlock()
token := tokens[currentIdx].Token token := tokens[currentIdx].Token
log.Printf("[outGetAllGoods] 使用token索引: %d/%d, username=%s", currentIdx, len(tokens), tokens[currentIdx].Username)
//kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&quaSelect=2"
kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2" kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2"
// 整理查询参数-加上排序 // 整理查询参数-加上排序
@ -260,6 +285,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
// 加入查询参数 // 加入查询参数
kfzUrl = kfzUrl + "&actionPath=" + actionPath kfzUrl = kfzUrl + "&actionPath=" + actionPath
log.Printf("[outGetAllGoods] 请求孔网URL: %s", kfzUrl)
// 创建HTTP客户端 // 创建HTTP客户端
requestSpt := gorequest.New() requestSpt := gorequest.New()
@ -267,7 +294,6 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
if s.proxy != "" { if s.proxy != "" {
requestSpt.Proxy(s.proxy) requestSpt.Proxy(s.proxy)
} }
fmt.Println("请求地址:", kfzUrl)
// 发送请求 // 发送请求
respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl). respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl).
Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)).
@ -280,16 +306,16 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
// 错误处理 // 错误处理
if len(errsSpt) > 0 { if len(errsSpt) > 0 {
log.Printf("[outGetAllGoods] 孔网请求失败: %v", errsSpt)
return nil, fmt.Errorf("请求失败: %v", errsSpt) return nil, fmt.Errorf("请求失败: %v", errsSpt)
} }
// 检查HTTP状态码 // 检查HTTP状态码
if respSpt.StatusCode != http.StatusOK { if respSpt.StatusCode != http.StatusOK {
log.Printf("[outGetAllGoods] 孔网HTTP错误: %s", respSpt.Status)
return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status) return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status)
} }
fmt.Println("响应数据:", bodySpt)
// 解析响应 // 解析响应
var apiSptResp struct { var apiSptResp struct {
Status int `json:"status"` Status int `json:"status"`
@ -318,16 +344,19 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
// 解析JSON // 解析JSON
if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil { if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil {
log.Printf("[outGetAllGoods] 解析孔网响应JSON失败: %v", err)
return nil, fmt.Errorf("解析JSON失败: %w", err) return nil, fmt.Errorf("解析JSON失败: %w", err)
} }
if apiSptResp.Status != 1 { if apiSptResp.Status != 1 {
log.Printf("[outGetAllGoods] 孔网API返回错误: message=%s, errType=%s", apiSptResp.Message, apiSptResp.ErrType)
return nil, fmt.Errorf("错误信息: %v状态码: %s", apiSptResp.Message, apiSptResp.ErrType) return nil, fmt.Errorf("错误信息: %v状态码: %s", apiSptResp.Message, apiSptResp.ErrType)
} }
bookInfo := &model.BookInfo{} bookInfo := &model.BookInfo{}
if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 { if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 {
log.Printf("[outGetAllGoods] 孔网搜索成功: 总共%d条结果, query_index=%d", apiSptResp.Data.ItemResponse.Total, queryIndex)
if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) { if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) {
goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1] goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1]
bookInfo.BookName = goodsInfo.Title bookInfo.BookName = goodsInfo.Title
@ -339,6 +368,7 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
for _, shipping := range goodsInfo.Postage.ShippingList { for _, shipping := range goodsInfo.Postage.ShippingList {
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee) bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
} }
log.Printf("[outGetAllGoods] 取第%d条结果: title=%s, price=%s, shipping=%s", queryIndex, bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee)
} else { } else {
goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1] goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1]
bookInfo.BookName = goodsInfo.Title bookInfo.BookName = goodsInfo.Title
@ -350,9 +380,11 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
for _, shipping := range goodsInfo.Postage.ShippingList { for _, shipping := range goodsInfo.Postage.ShippingList {
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee) bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
} }
log.Printf("[outGetAllGoods] query_index无效, 取最后一条: title=%s, price=%s, shipping=%s", bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee)
} }
return bookInfo, nil return bookInfo, nil
} }
log.Printf("[outGetAllGoods] 孔网搜索无结果: total=%d", apiSptResp.Data.ItemResponse.Total)
return nil, fmt.Errorf("查询失败,没有数据!") return nil, fmt.Errorf("查询失败,没有数据!")
} }