当前位置: 首页 > news >正文

JAVA SDK通过proxy对接google: GCS/FCM

前言:因为国内调用google相关api需要通过代理访问(不想设置全局代理),所以在代理这里经常遇到问题,先说一下结论 GCS 需要设置全局代理或自定义代理选择器, FCM sdk admin 在初始化firebaseApp时是支持设置的。

GCS: 开始时尝试在使用sdk时传入代理的配置,但没有实际效果。

参考如下资料:

https://stackoverflow.com/questions/49980303/how-to-set-proxy-for-storage-service-in-gcp-using-java

最终选择如下资料中的方案使用自定义代理选择器解决了问题:

Java Networking and Proxies

@Slf4j
public class CustomProxySelector extends ProxySelector {
    private final ProxySelector defaultSelector;

    private final Proxy proxy;

    private final Set<String> targetDomains;

    public CustomProxySelector(ProxySelector defaultSelector, Proxy proxy, Set<String> targetDomains) {
        this.defaultSelector = defaultSelector;
        this.proxy = proxy;
        this.targetDomains = targetDomains;
    }

    // 根据 URL 选择代理
    @Override
    public List<Proxy> select(URI uri) {
        if (uri != null && uri.getHost() != null) {
            log.info("uri:{}", uri.getHost());
            for (String domain : targetDomains) {
                if (uri.getHost().endsWith(domain)) {
                    log.info("uri google:{} proxy:{}", uri.getHost(), proxy.toString());
                    return List.of(proxy);
                }
            }
        }
        return defaultSelector.select(uri);
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        defaultSelector.connectFailed(uri, sa, ioe);
    }

}


@Slf4j
@Component
public class ProxyConfigurer {
    @Value("${gateway.google.map-proxy.enable:false}")
    private boolean proxyEnabled;

    @Value("${gateway.google.map-proxy.host:}")
    private String proxyHost;

    @Value("${gateway.google.map-proxy.port:}")
    private int proxyPort;

    @PostConstruct
    public void configureProxy() {
        if (!proxyEnabled) {
            return;
        }
        log.info("proxyHost:{} port:{}", proxyHost, proxyPort);
        ProxySelector defaultSelector = ProxySelector.getDefault();
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
        Set<String> targetDomains = new HashSet<>(List.of(".googleapis.com"));

        CustomProxySelector customSelector = new CustomProxySelector(defaultSelector, proxy, targetDomains);
        ProxySelector.setDefault(customSelector);
        log.info("Proxy selector configured successfully.");
    }

}

FCM:

这个因为是后面我才开始对接我直接就选择了代理选择器方式发现本地好用,但服务器上就不好用,报错如下:

Caused by: java.io.IOException: Unknown exception in request
    at com.google.firebase.internal.ApacheHttp2Request.execute(ApacheHttp2Request.java:134)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1012)
    at com.google.firebase.internal.ErrorHandlingHttpClient.send(ErrorHandlingHttpClient.java:97)
    ... 38 more
Caused by: java.util.concurrent.ExecutionException: java.net.SocketException: Network is unreachable
    at org.apache.hc.core5.concurrent.BasicFuture.getResult(BasicFuture.java:72)
    at org.apache.hc.core5.concurrent.BasicFuture.get(BasicFuture.java:85)
    at com.google.firebase.internal.ApacheHttp2Request.execute(ApacheHttp2Request.java:123)
    ... 40 more
Caused by: java.net.SocketException: Network is unreachable

开始怀疑是proxy有问题,这时候一般选择用curl测试proxy是否连通

curl -I --proxy xxx:3128 "https://oauth2.googleapis.com/token"

返回404 代表网络上是通的,后来查询文档Firebase: Accessing Firestore and Firebase through a proxy server | by Hiranya Jayathilaka | FAUN — Developer Community 🐾

其实SDK是支持动态设置的,但文档中与我的实现有出入所以参照源码加了一个动态的令牌鉴权改造代码如下:

@PostConstruct
    private void initializeFirebase() {
        try {
            InputStream inputStream = fileServiceUtil.downloadFile(fcmPath);
            if (inputStream == null) {
                log.error("fcm file download fail");
                throw new GeneraliPluginException("fcm file download fail");
            }
            InetSocketAddress address = new InetSocketAddress(proxyHost, proxyPort);
            final HttpTransport transport = new NetHttpTransport.Builder()
                .setProxy(new Proxy(Proxy.Type.HTTP, address))
                .build();
            HttpTransportFactory transportFactory = () -> transport;

            FirebaseOptions options =
                FirebaseOptions.builder()
                    .setCredentials(GoogleCredentials.fromStream(inputStream, transportFactory))
                    .setHttpTransport(transport)
                    .build();
            FirebaseApp.initializeApp(options);
        } catch (IOException e) {
            Log.error("PushNotificationServiceAndroidImpl.initializeFirebase", e);
        }
    }

解决问题。 

思考:还是要以官网文档和各种社区讨论来编写代码,经常查询各种社区是非常有帮助的。

相关文章:

  • 实测解析:FP7208 在汽车照明、摄影照明、教育照明以及太阳能照明等不同市场领域的典型应用参数解析和案例分析
  • Kingbase 常用运维命令总结
  • Vue的学习总结-day02
  • Pinyin4j修仙指南:从汉字到拼音的声韵转换大法
  • 部署Fish-Speech实现声音克隆及文本转语音
  • Windows 系统中安装 Git 并配置 GitHub 账户
  • C++基本语法
  • 【C语言】--- 编译和链接
  • C语言程序环境和预处理详解
  • centos7.9升级OpenSSL 1.1.1
  • 代码随想录算法训练营Day23
  • 强化学习的epsilon,应该越来越大?还是越来越小?为什么?
  • 面向对象高级(2)
  • Apache与Nginx网站压测对比
  • C语言 共用体和typedef
  • 集群搭建Weblogic服务器!
  • C++学习之金融类安全传输平台项目git
  • 第十五届蓝桥杯C/C++B组省赛真题讲解(分享去年比赛的一些真实感受)
  • 智体知识库:poplang编程语言是什么?
  • 具身机器人中AI(DEEPSEEK)与PLC、驱动器协同发展研究:突破数据困境与指令精确控制(1)
  • 建网站需要什么程序/seo网站优化教程
  • 赌博类网站开发犯罪吗/宁波seo快速优化公司
  • 北京模板网站制作/关键词怎样做优化排名
  • 如何做物流网站/seo怎么做新手入门
  • 小程序询价表/seo百度点击软件
  • 网站优化成本/重庆网站制作公司哪家好