求助:如何为Google Translate API v3配置网络代理?
Google Translate API v3 代理配置问题解决方案
在国内环境下,Google Translate API v2通过自定义HTTP客户端配置代理可正常工作,但v3版本配置代理后无法生效,且全局代理会导致本地etcd服务连接超时(错误信息如下):
// etcd.test.com it is local domain
{
"level": "warn",
"ts": "2025-01-21T22:12:18.592216+0800",
"logger": "etcd-client",
"caller": "v3@v3.5.9/retry_interceptor.go:62",
"msg": "retrying of unary invoker failed",
"target": "etcd-endpoints://0xc0006c7500/etcd.test.com:2379",
"attempt": 0,
"error": "rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded"
}
核心问题分析
- Google Translate API v3基于gRPC协议,v2基于HTTP,两者代理配置逻辑完全不同
- 全局修改
http.DefaultTransport会强制所有请求(包括本地etcd)走代理,引发本地服务连接超时 - 原v3代码同时配置gRPC DialOption和HTTPClient,逻辑冲突且未区分本地与外部请求
修正后的v3代理配置代码
import ( "context" "fmt" "net" "net/http" "net/url" "strings" "crypto/tls" "cloud.google.com/go/translate/apiv3" "cloud.google.com/go/translate/apiv3/translatepb" "google.golang.org/api/option" "google.golang.org/grpc" "google.golang.org/grpc/resolver/dns" ) func (r *GoogleV3) Translate(text, source, target string) (string, error) { ctx := context.Background() proxyURL, err := url.Parse("http://192.168.252.103:1082") if err != nil { return "", fmt.Errorf("parse proxy URL: %w", err) } // 自定义拨号器:本地服务直接连接,外部请求走代理 proxyDialer := func(ctx context.Context, addr string) (net.Conn, error) { // 识别本地域名,可根据需要添加更多本地服务地址 localDomains := []string{"etcd.test.com"} isLocal := false for _, domain := range localDomains { if strings.Contains(addr, domain) { isLocal = true break } } if isLocal { // 本地服务直接拨号 return (&net.Dialer{}).DialContext(ctx, "tcp", addr) } // 外部请求通过代理建立连接,并完成TLS握手(gRPC基于HTTPS) proxyConn, err := http.ProxyURL(proxyURL).Dial(ctx, "tcp", addr) if err != nil { return nil, fmt.Errorf("proxy dial failed: %w", err) } serverName := strings.Split(addr, ":")[0] tlsConn := tls.Client(proxyConn, &tls.Config{ServerName: serverName}) if err := tlsConn.Handshake(); err != nil { proxyConn.Close() return nil, fmt.Errorf("TLS handshake failed: %w", err) } return tlsConn, nil } // 配置gRPC拨号选项 dialOpts := []grpc.DialOption{ grpc.WithContextDialer(proxyDialer), // 确保DNS解析时,本地域名不走代理 grpc.WithResolvers(&dns.Resolver{ Dial: func(ctx context.Context, network, address string) (net.Conn, error) { return proxyDialer(ctx, address) }, }), } // 构建客户端选项 clientOpts := []option.ClientOption{ option.WithGRPCDialOption(dialOpts...), option.WithCredentialsFile("d:/local-develop-394606-0320bb3d0ef2.json"), } client, err := translate.NewTranslationClient(ctx, clientOpts...) if err != nil { return "", fmt.Errorf("create translation client failed: %w", err) } defer client.Close() projectID := "387535220975" req := &translatepb.TranslateTextRequest{ Parent: fmt.Sprintf("projects/%s/locations/global", projectID), SourceLanguageCode: source, TargetLanguageCode: target, MimeType: "text/plain", Contents: []string{text}, } resp, err := client.TranslateText(ctx, req) if err != nil { return "", fmt.Errorf("translate text failed: %w", err) } txt := "" for _, translation := range resp.GetTranslations() { txt += translation.TranslatedText } return txt, nil }
关键修改说明
- 取消全局代理:不再修改
http.DefaultTransport,避免影响本地服务的正常请求 - 请求区分处理:自定义拨号器识别本地域名,仅Google API的外部请求走代理
- 适配gRPC协议:手动处理TLS握手,符合gRPC的HTTPS通信要求
- 优化DNS解析:自定义DNS resolver,确保本地域名解析不经过代理
- 精简冗余配置:移除
WithHTTPClient配置,v3客户端默认使用gRPC协议,无需HTTP客户端
内容的提问来源于stack exchange,提问作者hhniao
相关产品推荐
相关产品推荐

