使用APNS或JavaAPNS发送推送通知时获取javax.net.ssl.SSLHandshakeException

时间:2015-08-08 13:14:12

标签: java exception ssl apple-push-notifications sslhandshakeexception

使用Java服务器应用程序,该应用程序将Apple推送通知发送给用户。

在最近几天工作以解决SSL握手问题,获取" javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接"当我的Java服务器应用程序尝试发送APNS消息时

尝试了两个独立的库APNS(https://github.com/notnoop/java-apns_和Java-APNS(https://code.google.com/p/javapns/),但在两种情况下都遇到了同样的问题

这是我的APNS示例代码

@Service(value = "apnsPushService")
public class APNSPushService extends AbstractPushService    {

    protected String certificate = null;
    protected String passphrase = null;
    private ApnsService service = null;

    @Override
    @PostConstruct
    public void init() throws Exception {
    super.init();
    try {
        service = buildApnsService();
        service.start();
    } catch (Exception e) {
        logger.error("While building the APNS service", e);
        throw e;
    }
}

@Override
public boolean pushMessage(String notificationKey, String message) throws Exception {
    PayloadBuilder builder = APNS.newPayload().alertBody(alert) // alert dialog, in iOS
        .badge(badge) // little badge icon update;
        .sound(sound); // sound to be played by app

    builder = builder.alertBody(message);

    final String apnsMessage = builder.build(); // build the JSON payload for APNs
    logger.info("Sending transformed APNs payload: " + apnsMessage);

    service.push(notificationKey, apnsMessage, createFutureDateBasedOnTTL(timeToLive));
    return true;
}

/**
* Helper method that creates a future {@link Date}, based on the given ttl/time-to-live value. If no TTL was provided, we use the max date from
* the APNs library
*/
private Date createFutureDateBasedOnTTL(int ttl) {

    // no TTL was specified on the payload, we use the MAX Default from the
    // APNs library:
    if (ttl == -1) {
        return new Date(System.currentTimeMillis() + EnhancedApnsNotification.MAXIMUM_EXPIRY * 1000L);
    } else {
        // apply the given TTL to the current time
        return new Date(System.currentTimeMillis() + ttl);
    }
}

/**
* Build the APNS Service
* 
* @return
*/
private ApnsService buildApnsService() throws Exception {
    ApnsService apnsService = null;
    // this check should not be needed, but you never know:
    if (certificate != null && passphrase != null) {

        final ApnsServiceBuilder builder = APNS.newService();
        try(InputStream stream = new FileInputStream(certificate)) {
            builder.withCert(stream, passphrase);

            // pick the destination:
            if (production) {
                builder.withProductionDestination();
            } else {
                builder.withSandboxDestination();
            }
        }

        // create the service
        return builder.build();
    }

    return apnsService;
}

@Value("${apns.certificate}")
public void setCertificate(String certificate) {
    this.certificate = certificate;
}

@Value("${apns.passphrase}")
public void setPassphrase(String passphrase) {
    this.passphrase = passphrase;
}

@Value("${apns.production}")
public void setProduction(String production) {
    this.production = Boolean.parseBoolean(production);
}

@Value("${apns.alert}")
public void setAlert(String alert) {
    this.alert = alert;
}

@Value("${apns.sound}")
public void setSound(String sound) {
    this.sound = sound;
}

@Value("${apns.badge}")
public void setBadge(String badge) {
    this.badge = Integer.parseInt(badge);
}

@Value("${apns.timetolive}")
public void setTimeToLive(String timeToLive) {
    this.timeToLive = Integer.parseInt(timeToLive);
}
}

这是我的Java APNS代码 -

public class JavaAPNSPushService extends AbstractPushService {

protected String certificate = null;
protected String passphrase = null;

private PushQueue queue = null;

private int counter = 1;

@Override
@PostConstruct
public void init() throws Exception {
super.init();
queue= Push.queue(certificate, passphrase, production, 10);
queue.start();

}

@Override
public boolean pushMessage(String notificationKey, String message) throws Exception 
{
    if (counter++ > 1000) {
        counter = 1;
        queue.clearPushedNotifications();
    }

    PushNotificationPayload payload = new PushNotificationPayload(alert, badge, sound);
    payload.addAlert(message);
    payload.setExpiry(timeToLive);

    PushQueue tempQueue = queue.add(payload, notificationKey);

    List<Exception> expList = tempQueue.getCriticalExceptions();
    if (expList.size() > 0) {
        expList.get(0).printStackTrace();
    }

    PushedNotification notification =      tempQueue.getPushedNotifications().firstElement();
    while(!notification.isTransmissionCompleted()) {
        Thread.sleep(100);
    }

    return notification.isSuccessful();
}

    @Value("${apns.certificate}")
    public void setCertificate(String certificate) {
        this.certificate = certificate;
    }

    @Value("${apns.passphrase}")
    public void setPassphrase(String passphrase) {
        this.passphrase = passphrase;
    }

    @Value("${apns.production}")
    public void setProduction(String production) {
        this.production = Boolean.parseBoolean(production);
    }

    @Value("${apns.alert}")
    public void setAlert(String alert) {
        this.alert = alert;
    }

    @Value("${apns.sound}")
    public void setSound(String sound) {
        this.sound = sound;
    }

    @Value("${apns.badge}")
    public void setBadge(String badge) {
        this.badge = Integer.parseInt(badge);
    }

    @Value("${apns.timetolive}")
    public void setTimeToLive(String timeToLive) {
        this.timeToLive = Integer.parseInt(timeToLive);
    }

}

这是我的异常堆栈跟踪 -

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:728)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
    at java.io.OutputStream.write(OutputStream.java:75)
    at javapns.notification.PushNotificationManager.sendNotification(PushNotificationManager.java:402)
    at javapns.notification.PushNotificationManager.sendNotification(PushNotificationManager.java:350)
    at javapns.notification.PushNotificationManager.sendNotification(PushNotificationManager.java:320)
    at javapns.Push.sendPayload(Push.java:177)
    at javapns.Push.test(Push.java:132)
    at com.aaplab.konvx.push.apns.JavaAPNSPushService.pushMessage(JavaAPNSPushService.java:69)
    at com.aaplab.konvx.push.AbstractPushService.push(AbstractPushService.java:61)
    at com.aaplab.konvx.PushTest.JavaAPNSPushTest(PushTest.java:36)
    at com.aaplab.konvx.PushTest.main(PushTest.java:23)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(InputRecord.java:505)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
    ... 13 more

已经遵循了以下各种建议:

  1. 从私钥创建.p12证书文件,从Apple重新下载证书。重复多次,但没有运气。

  2. 确保认证是开发模式而非生产模式。

  3. 即使尝试使用信任所有证书的示例代码,仍然会遇到同样的问题。

  4. 虽然我已经成功地远程登录&#34; gateway.sandbox.push.apple.com&#34; / 2195但是当涉及到java代码时,事情无法正常工作。

    它肯定不是代理问题,因为我已经从我的Windows机器以及我们的生产服务器测试过它,双方都失败了。

    不批量发送邮件,只是尝试发送单个邮件并且邮件失败。

0 个答案:

没有答案