fadd
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -163,7 +164,7 @@ func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData m
|
||||
"Content-Type": "application/json",
|
||||
headerDmsToken: token,
|
||||
}
|
||||
curlCmd := generateCurlCommand(http.MethodPost, requestURL, headers, bodyStr)
|
||||
curlCmd := generateCurlCommand(http.MethodPost, requestURL, headers, bodyStr, s.config.Proxy)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestURL, bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
@@ -298,7 +299,7 @@ func (s *RongxingService) login(ctx context.Context, transactionID string) (stri
|
||||
bodyStr := string(bodyBytes)
|
||||
|
||||
headers := map[string]string{"Content-Type": "application/json"}
|
||||
curlCmd := generateCurlCommand(http.MethodPost, requestURL, headers, bodyStr)
|
||||
curlCmd := generateCurlCommand(http.MethodPost, requestURL, headers, bodyStr, s.config.Proxy)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestURL, bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
@@ -356,7 +357,7 @@ func (s *RongxingService) login(ctx context.Context, transactionID string) (stri
|
||||
func (s *RongxingService) doHTTP(req *http.Request) ([]byte, int, error) {
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, s.wrapTransportError(req.URL.String(), err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -367,6 +368,48 @@ func (s *RongxingService) doHTTP(req *http.Request) ([]byte, int, error) {
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
// wrapTransportError 把超时/拒连/代理失败等包装成可读诊断,便于区分「联不通」原因。
|
||||
func (s *RongxingService) wrapTransportError(targetURL string, err error) error {
|
||||
diag := classifyTransportError(err)
|
||||
proxyMode := strings.TrimSpace(s.config.Proxy)
|
||||
if proxyMode == "" {
|
||||
proxyMode = "(直连,未配置 proxy)"
|
||||
}
|
||||
return fmt.Errorf(
|
||||
"戎行 HTTP 失败 target=%s proxy=%s diagnosis=%s cause=%w",
|
||||
targetURL, proxyMode, diag, err,
|
||||
)
|
||||
}
|
||||
|
||||
func classifyTransportError(err error) string {
|
||||
if err == nil {
|
||||
return "unknown"
|
||||
}
|
||||
msg := err.Error()
|
||||
|
||||
switch {
|
||||
case os.IsTimeout(err) || errors.Is(err, context.DeadlineExceeded) ||
|
||||
strings.Contains(msg, "Client.Timeout") || strings.Contains(msg, "deadline exceeded"):
|
||||
return "请求超时(未在 timeout 内收到响应头;可能:目标 192.168.3.43:7007 不可达、VPN/SOCKS 未转发、或服务无响应)"
|
||||
case strings.Contains(msg, "connection refused"):
|
||||
return "连接被拒绝(端口未监听或代理/目标拒绝)"
|
||||
case strings.Contains(msg, "no such host") || strings.Contains(msg, "lookup"):
|
||||
return "DNS/主机名解析失败(检查 rongxing-vpn 服务名或目标域名)"
|
||||
case strings.Contains(msg, "network is unreachable") || strings.Contains(msg, "no route to host"):
|
||||
return "网络不可达(无路由;直连内网 IP 时常见于未走 VPN/代理)"
|
||||
case strings.Contains(msg, "i/o timeout") || strings.Contains(msg, "TLS handshake timeout"):
|
||||
return "传输层超时(链路通但握手/读写超时)"
|
||||
case strings.Contains(msg, "proxy") || strings.Contains(msg, "socks"):
|
||||
return "代理链路异常(检查 socks5://rongxing-vpn:1080 与 VPN 容器)"
|
||||
}
|
||||
|
||||
var netErr net.Error
|
||||
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||
return "网络超时"
|
||||
}
|
||||
return "其他网络错误(详见 cause)"
|
||||
}
|
||||
|
||||
func (s *RongxingService) validateConfig() error {
|
||||
if s.config.BaseURL == "" {
|
||||
return errors.New("戎行 url 未配置")
|
||||
@@ -429,12 +472,35 @@ func (s *RongxingService) logErrorWithCurl(transactionID, apiKey string, err err
|
||||
if s.logger == nil {
|
||||
return
|
||||
}
|
||||
proxyMode := strings.TrimSpace(s.config.Proxy)
|
||||
if proxyMode == "" {
|
||||
proxyMode = "(直连,未配置 proxy)"
|
||||
}
|
||||
s.logger.LogErrorWithFields("rongxing API错误",
|
||||
zap.String("transaction_id", transactionID),
|
||||
zap.String("api_code", apiKey),
|
||||
zap.String("base_url", s.config.BaseURL),
|
||||
zap.String("proxy", proxyMode),
|
||||
zap.String("diagnosis", extractDiagnosis(err)),
|
||||
zap.Error(err),
|
||||
zap.Any("params", payload),
|
||||
zap.String("curl", curlCmd),
|
||||
zap.String("response_body", respBody),
|
||||
)
|
||||
}
|
||||
|
||||
func extractDiagnosis(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
const marker = "diagnosis="
|
||||
msg := err.Error()
|
||||
if i := strings.Index(msg, marker); i >= 0 {
|
||||
rest := msg[i+len(marker):]
|
||||
if j := strings.Index(rest, " cause="); j >= 0 {
|
||||
return rest[:j]
|
||||
}
|
||||
return rest
|
||||
}
|
||||
return classifyTransportError(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user