从Google AppEngine调用FCM后端服务时出现异常求助
嘿,看起来你在从GCM迁移到FCM的过程中,在GAE标准环境下碰到了挺闹心的随机异常问题——一会儿是FCM后端调用失败,一会儿又连accounts.google.com都解析不了。我结合GAE和FCM的特性,给你梳理几个可能的原因和解决办法:
先拆解下你遇到的两个核心异常:
com.google.firebase.messaging.FirebaseMessagingException: Error while calling FCM backend service:这说明FCM Admin SDK没法正常和FCM后端完成通信java.net.UnknownHostException: accounts.google.com:你的GAE应用连Google账号服务的域名都解析不了,这大概率和GAE标准环境的网络限制有关
下面是针对性的修复方案:
1. 别重复初始化FirebaseApp!
你的代码里每次调用sendFCM()都会跑一遍initFCM(),但FirebaseApp.initializeApp(options)应该只在应用启动时执行一次,重复初始化会搞乱资源连接,很容易引发不稳定的异常。
修改方式:把初始化逻辑移到Servlet的启动阶段,或者用静态代码块确保只执行一次:
static { try { FileInputStream serviceAccount = new FileInputStream("WEB-INF/Orchestram-e2e1ceeb2481.json"); FirebaseOptions options = new FirebaseOptions.Builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .setDatabaseUrl("https://orchestram-cerqana.firebaseio.com/") .build(); // 先检查有没有已初始化的实例,避免重复调用 if (FirebaseApp.getApps().isEmpty()) { FirebaseApp.initializeApp(options); } } catch (Exception e) { e.printStackTrace(); } }
2. 适配GAE的网络访问规则
GAE标准环境不允许用Java原生的Socket连接,必须用Google提供的UrlFetch服务。但FCM Admin SDK默认的HTTP客户端可能不兼容这个规则,得手动配置成UrlFetchHttpClient:
在初始化FirebaseOptions的时候加上这个配置:
import com.google.firebase.http.UrlFetchHttpClient; // ... FirebaseOptions options = new FirebaseOptions.Builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .setDatabaseUrl("https://orchestram-cerqana.firebaseio.com/") // 强制使用UrlFetch适配GAE环境 .setHttpClient(new UrlFetchHttpClient()) .build();
如果用Maven的话,记得确认依赖里包含firebase-http库:
<dependency> <groupId>com.google.firebase</groupId> <artifactId>firebase-http</artifactId> <version>和你的Firebase Admin SDK版本一致</version> </dependency>
3. 检查服务账号的权限
确认你的服务账号JSON对应的账号有FCM发送权限,最简单的方式是给它加个「Cloud Messaging Admin」角色:
- 登录Google Cloud Console找到你的项目
- 进入「IAM与管理员」→「IAM」页面
- 找到对应的服务账号,添加角色「Cloud Messaging」→「Cloud Messaging Admin」
4. 别用get()阻塞异步调用
sendAsync(message).get()会同步阻塞线程等结果,在GAE环境下这种阻塞很容易触发请求超时或者资源限制。建议改用异步回调的方式处理:
FirebaseMessaging.getInstance().sendAsync(message) .thenAccept(response -> { // 处理发送成功的逻辑 System.out.println("FCM消息发出去啦: " + response); }) .exceptionally(e -> { // 处理异常逻辑 e.printStackTrace(); return null; });
5. 确认GAE的网络访问权限
检查你的GAE应用有没有对外网络访问权限(默认是允许的,但如果配置了VPC连接器可能要额外调整),同时确认防火墙规则没拦住对fcm.googleapis.com和accounts.google.com的访问。
按照这些步骤逐一排查,应该能解决你碰到的随机异常问题。
内容的提问来源于stack exchange,提问作者Alfonso

