fish2018/pansou · error

解析代理地址失败

Error message

解析代理地址失败: %w

What it means

When building an HTTP transport that routes through a proxy, the plugin parses config.AppConfig.ProxyURL with url.Parse. If the configured proxy string is not a valid URL, url.Parse returns an error which is wrapped as '解析代理地址失败: %w'. This happens before any network connection is attempted — it is purely a configuration parsing failure.

Solutions

  1. Fix ProxyURL in the config to a well-formed absolute URL, e.g. socks5://127.0.0.1:1080 or http://user:pass@proxy:8080 (URL-encode credentials with url.UserPassword).
  2. Trim whitespace and check the value actually parsed — log url.Parse's error detail from the wrapped %w to see the offending component.
  3. Pre-validate the proxy string at config-load time with url.Parse and fail fast with a clear message.
  4. Remove the proxy setting entirely if no proxy is needed, so the non-proxy transport branch is used.

Example fix

// before
ProxyURL = "socks5:// 127.0.0.1:1080"        // space -> parse error
// after
ProxyURL = "socks5://127.0.0.1:1080"          // valid
// optional guard
if _, err := url.Parse(cfg.ProxyURL); err != nil { return fmt.Errorf("invalid proxy URL %q: %w", cfg.ProxyURL, err) }
Defensive patterns

Strategy: validation

Validate before calling

func validProxyURL(s string) bool {
    if s == "" { return true } // no proxy is fine
    u, err := url.Parse(strings.TrimSpace(s))
    return err == nil && u.Scheme != "" && u.Host != ""
}
// check before setting AppConfig.ProxyURL or before transport setup

Try / catch

transport, err := buildProxyTransport(cfg)
if err != nil {
    if strings.Contains(err.Error(), "解析代理地址失败") {
        log.Warnf("bad proxy URL %q, falling back to direct", cfg.ProxyURL)
        transport = defaultTransport()
    } else { return err }
}

Prevention

When it happens

Trigger: ProxyURL in the application config is set to a malformed value (e.g. missing scheme, spaces, invalid characters, 'http://[bad-ipv6', or a bare 'host:port' with stray characters) and the plugin initializes its proxy-aware transport.

Common situations: User typo in the proxy setting; environment-specific config with unescaped characters; copying a SOCKS URI like 'socks5://user:pass@host:port' with an unencoded password containing '@' or ':'; empty-but-present string or whitespace from an env var.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/cc698f66f5795a1c. Report an issue: GitHub.

Appendix: source

Thrown at plugin/gying/gying.go:1634

	if transportValue.Kind() != reflect.Ptr || transportValue.IsNil() {
		return fmt.Errorf("scraper transport 无效")
	}

	transportElem := transportValue.Elem()
	baseTransportField := transportElem.FieldByName("Transport")
	if !baseTransportField.IsValid() || baseTransportField.IsNil() {
		return fmt.Errorf("未找到底层 transport")
	}

	baseTransportValue := reflect.NewAt(baseTransportField.Type(), unsafe.Pointer(baseTransportField.UnsafeAddr())).Elem()
	baseTransport, ok := baseTransportValue.Interface().(*http.Transport)
	if !ok || baseTransport == nil {
		return fmt.Errorf("底层 transport 无效")
	}

	proxyURL, err := url.Parse(config.AppConfig.ProxyURL)
	if err != nil {
		return fmt.Errorf("解析代理地址失败: %w", err)
	}

	if proxyURL.Scheme == "socks5" {
		dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
		if err != nil {
			return fmt.Errorf("创建SOCKS5代理失败: %w", err)
		}
		baseTransport.Proxy = nil
		baseTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
			return dialer.Dial(network, addr)
		}
	} else {
		baseTransport.Proxy = http.ProxyURL(proxyURL)
	}

	if DebugLog {
		fmt.Printf("[Gying] 已应用代理到scraper: %s\n", config.AppConfig.ProxyURL)
	}

View on GitHub (pinned to beaa561337)