推送服务报错

aylitat 12小时前 57

服务端后台已经配置了IOS-APNS相关信息,测试推送正常。 走实际推送报错。报错原因是 Destination topic must not be null.。 看文档,包名好像不是必填项啊? 另外问一下,有没有推送的独立flutter-SDK? `2026-05-20 16:00:36.688 INFO 32564 --- [nio-8085-exec-6] c.w.push.ios.IOSPushServiceImpl : iOS push {"sender":"2007723292","senderName":"77777777","convType":3,"target":"1765105749","targetName":"You have a new message.","line":0,"cntType":0,"serverTime":1779264036644,"pushMessageType":0,"pushType":1,"pushContent":"You have a new message.","unReceivedMsg":3,"mentionedType":0,"deviceToken":"af69ca07db8dbb90feef1719...dd305ae23b53","isHiddenDetail":false,"language":"zh","messageId":0,"callStartUid":0,"republish":false,"existBadgeNumber":0} 2026-05-20 16:00:36.689 ERROR 32564 --- [nio-8085-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Destination topic must not be null.] with root cause

java.lang.NullPointerException: Destination topic must not be null. at java.base/java.util.Objects.requireNonNull(Objects.java:233) ~[na:na] at com.turo.pushy.apns.util.SimpleApnsPushNotification.(SimpleApnsPushNotification.java:195) ~[pushy-0.13.10.jar!/:na] at cn.wildfirechat.push.ios.ApnsServer.pushMessage(ApnsServer.java:272) ~[classes!/:0.1.2] at cn.wildfirechat.push.ios.IOSPushServiceImpl.push(IOSPushServiceImpl.java:66) ~[classes!/:0.1.2] at cn.wildfirechat.push.PushController.iOSPush(PushController.java:30) ~[classes!/:0.1.2] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.34.jar!/:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at cn.wildfirechat.push.admin.PortAccessFilter.doFilterInternal(PortAccessFilter.java:55) ~[classes!/:0.1.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.10.RELEASE.jar!/:5.0.10.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-8.5.34.jar!/:8.5.34] at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]

2026-05-20 16:02:25.087 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@51115e12 (No operations allowed after connection closed.) 2026-05-20 16:02:25.088 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@4da09916 (No operations allowed after connection closed.) 2026-05-20 16:02:25.089 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@121a28b0 (No operations allowed after connection closed.) 2026-05-20 16:02:25.090 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@2f420850 (No operations allowed after connection closed.) 2026-05-20 16:02:25.090 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@74783264 (No operations allowed after connection closed.) 2026-05-20 16:02:25.091 WARN 32564 --- [pool-2-thread-1] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@3dd97dd4 (No operations allowed after connection closed.)`

最新回复 (2)
  • wfclaw 12小时前
    引用 2
    你好,这个问题的原因是 **APNS 推送时 bundle ID(topic)为空** 导致的。

    **原因分析**

    报错 `Destination topic must not be null` 发生在 `ApnsServer.pushMessage` 中,是因为 `pushMessage.packageName` 为空。

    从 push-server 代码可以看到:
    ```java
    pushMessage.packageName = session.getAppName();
    ```

    `packageName` 是从 im-server 的 session 中取的 `appName`。如果 session 没有 appName,推送时 topic 就是空的,APNS 就会报错。

    **iOS 客户端的 bundle ID 是通过 `setDeviceToken` 上报的**

    iOS SDK 中设置推送 token 的接口是:
    ```objc
    setDeviceToken(appName, deviceToken, pushType)
    ```

    第一个参数 `appName` 就是 bundle ID。如果调用时传了空字符串或 nil,im-server 的 session 就保存不了 appName,后续 APNS 推送就会因为缺少 topic 而失败。

    **解决方案**

    请检查 iOS 客户端代码中 `setDeviceToken` 的调用,确保第一个参数传了正确的 bundle ID:

    ```objc
    // 正确示例
    [[WFCCNetworkService sharedInstance] setDeviceToken:[[NSBundle mainBundle] bundleIdentifier] 
                                          deviceToken:token 
                                            pushType:1];
    ```

    **关于 Flutter SDK**

    push-server 本身没有独立的 Flutter SDK。野火 IM 的推送能力是通过各平台的原生 SDK 封装的。Flutter 项目中需要集成各平台(iOS/Android)的原生推送逻辑,然后由 im-server 统一调用 push-server 进行推送。

    Flutter 客户端可以参考官方各平台原生 SDK 的集成方式,或者微信联系 **wfchat** 咨询 Flutter 推送的最佳实践。
  • wfclaw 1小时前
    引用 3
    这个错误的原因是 iOS 推送时 APNs topic(即 bundle ID)为空导致的。

    **问题分析:**

    push-server 在调用 APNs 推送时,需要使用应用的 bundle ID 作为 APNs topic。这个值来自客户端登录时上报的 packagename。

    如果客户端没有正确上报 bundle ID,服务端在推送时就会抛出  错误。

    **排查方向:**

    1. **检查 iOS 客户端的 bundle ID**
       确保客户端登录时正确获取并上报了 CFBundleIdentifier:

       

    2. **检查 Info.plist**
       确认项目的 Info.plist 中正确配置了 ,且不为空。

    3. **自定义客户端的情况**
       如果你们对客户端进行了二次开发或使用了跨平台框架(如 Flutter/React Native),请检查是否正确实现了 DeviceInfo 上报逻辑,确保 packagename 字段有值。

    4. **应急处理**
       如果是服务端紧急修复,可以在 push-server 的  中增加空值判断,当 packageName 为空时给一个默认 bundle ID,但建议优先从客户端解决。

    **关于独立的 Flutter push SDK:**

    目前没有独立的 Flutter push SDK。推送功能依赖原生端的实现,Flutter 项目需要集成对应平台的推送插件(iOS 用 APNS,Android 用各厂商推送)。

    建议先检查客户端上报的 packagename 是否为空,这是最可能的原因。
返回