java.nio.channels.ClosedChannelException HTTP/2与jetty

java.nio.channels.ClosedChannelException HTTP/2与jetty,java,push-notification,apple-push-notifications,jetty-9,javapns,Java,Push Notification,Apple Push Notifications,Jetty 9,Javapns,我正在尝试使用HTTP/2向生产中的设备发送apple通知 我将这个-Xbootclasspath/p:/home/mohamed/Desktop/alpn-boot-8.1.9.v20160720.jar作为eclipse中的默认VM参数传递 以下是我现在使用的代码: public static void pushoNotification() { try { // create a low-level Jetty HTTP/2 client HTTP2

我正在尝试使用HTTP/2向生产中的设备发送apple通知

我将这个-Xbootclasspath/p:/home/mohamed/Desktop/alpn-boot-8.1.9.v20160720.jar作为eclipse中的默认VM参数传递

以下是我现在使用的代码:

public static void pushoNotification() {
    try {
        // create a low-level Jetty HTTP/2 client
        HTTP2Client lowLevelClient = new HTTP2Client();
        lowLevelClient.start();

        // APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
        KeyStore ks = KeyStore.getInstance("PKCS12");

        // Ensure that the password is the same as the one used later in setKeyStorePassword()
        ks.load(PushNotifications.class.getClassLoader().getResourceAsStream("Prod2.p12"), "a12B34".toCharArray());

        SslContextFactory ssl = new SslContextFactory(true);
        ssl.setKeyStore(ks);
        ssl.setKeyStorePassword("a12B34");

        // create a high-level Jetty client
        HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
        client.start();

        // request-response exchange
        ContentResponse response = client.POST("https://api.push.apple.com").path("/3/device/19297dba97212ac6fd16b9cd50f2d86629aed0e49576b2b52ed05086087da802")
                .content(new StringContentProvider("{ \"aps\" : { \"alert\" : \"Hello\" } }")).send();
        response.toString();
        client.stop();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
我的依赖关系

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.21</version>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty.http2</groupId>
        <artifactId>http2-http-client-transport</artifactId>
        <version>9.4.0.M1</version>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-http</artifactId>
        <version>9.4.0.M1</version>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty.http2</groupId>
        <artifactId>http2-client</artifactId>
        <version>9.4.0.M1</version>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-client</artifactId>
        <version>9.4.0.M1</version>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-alpn-client</artifactId>
        <version>9.4.0.M1</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.mortbay.jetty.alpn</groupId>
        <artifactId>alpn-boot</artifactId>
        <version>8.1.9.v20160720</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.8.2</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.8.2</version>
    </dependency>

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>3.4.1</version>
    </dependency>

org.slf4j
slf4j api
1.7.21
org.slf4j
slf4j简单
1.7.21
org.eclipse.jetty.http2
http2http客户端传输
9.4.0.M1
org.eclipse.jetty
jetty http
9.4.0.M1
org.eclipse.jetty.http2
http2客户端
9.4.0.M1
org.eclipse.jetty
码头客户机
9.4.0.M1
org.eclipse.jetty
jetty alpn客户端
9.4.0.M1
运行时
org.mortbay.jetty.alpn
阿尔卑斯靴
8.1.9.v20160720
运行时
com.fasterxml.jackson.core
杰克逊核心
2.8.2
com.fasterxml.jackson.core
杰克逊数据绑定
2.8.2
com.squareup.okhttp3
okhttp
3.4.1
但是当我从main方法运行这个方法时,它抛出java.nio.channels.ClosedChannelException

我在eclipse控制台中也得到了这个 INFO org.eclipse.jetty.http2.HTTP2Session-通知侦听器org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2时失败$SessionListenerPromise@87eaf9c

有什么想法吗


谢谢

在大约3年零6个月后,我现在粘贴我的答案只是为了帮助任何人得到相同的错误,实际上我不记得我是如何解决这个问题的,但这里有一个我现在正在使用的工作代码…

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myproject.path.model.APNSObject;

public void sendIOSNotification(APNSObject apnsObject, List<String> deviceIds, String notificationType) {
    HTTP2Client lowLevelClient = null;
    HttpClient client = null;
    String hostname = null;
    InputStream inputStream = null;
    try {

        lowLevelClient = new HTTP2Client(); // create a low-level Jetty HTTP/2 client
        lowLevelClient.start();

        // APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
        KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);

        inputStream = getClass().getClassLoader().getResourceAsStream(APPLE_CERTIFICATE_PATH);
        // Ensure that the password is the same as the one used later in setKeyStorePassword()
        ks.load(inputStream, APPLE_CERTIFICATE_PASSWORD.toCharArray());

        inputStream.close();

        SslContextFactory ssl = new SslContextFactory(true);
        ssl.setKeyStore(ks);
        ssl.setKeyStorePassword(APPLE_CERTIFICATE_PASSWORD);
        FuturePromise<Session> sessionPromise = new FuturePromise<>();

        if (notificationType != null && notificationType.trim().equalsIgnoreCase("Development"))
            hostname = APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME;
        else
            hostname = APPLE_NOTIFICATION_PRODUCTION_HOSTNAME;
        lowLevelClient.connect(ssl, new InetSocketAddress(hostname, Integer.parseInt(APPLE_NOTIFICATION_PORT)), new ServerSessionListener.Adapter(), sessionPromise);

        // create a high-level Jetty client
        client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
        client.start();

        // logger.info("Start Sending Notification.");
        for (String token : deviceIds) {
            ObjectMapper mapper = new ObjectMapper();
            String fcmJsonObject = mapper.setSerializationInclusion(Include.NON_NULL).setSerializationInclusion(Include.NON_EMPTY).writeValueAsString(apnsObject);
            Request request = client.POST("https://" + hostname).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
                        .content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
            request = request.header("apns-topic", APPLE_APNS_TOPIC);
            ContentResponse response = request.send();

            // For development mode if it's not passed in parameters
            if (response.getStatus() == 400 && !hostname.equals(APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME)) {
                request = client.POST("https://" + APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
                            .content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
                request = request.header("apns-topic", APPLE_APNS_TOPIC);
                response = request.send();
                logger.info("Sending notification to '" + token + "' in debugging mode...");
            }

            if (response.getStatus() == 200)
                logger.info("Date: " + new Date() + " Notification sent successfully to '" + token + "' With Response Status: " + response.getStatus());
            else
                logger.warning("Sending Notification to token '" + token + "' Failed :( >> Response Status: " + response.getStatus() + "\nReason: " +  response.getReason());
        }
        logger.info("End Sending Notification.");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (lowLevelClient != null && !lowLevelClient.isStopped())
                lowLevelClient.stop();
            if (client != null && !client.isStopped())
                client.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (inputStream != null)
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
这是我的配置文件:

APPLE_CERTIFICATE_PATH=/my/apply/certificate/path/so/plz/change/it/Certificates.p12
APPLE_CERTIFICATE_PASSWORD=myPassword(plz change it)
KEYSTORE_TYPE=PKCS12
APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME=api.development.push.apple.com
APPLE_NOTIFICATION_PRODUCTION_HOSTNAME=api.push.apple.com
APPLE_NOTIFICATION_PORT=2197
APPLE_APNS_TOPIC=MyAPNS_Topic(plz change it)
最后,这里是我在项目中使用的罐子:

APPLE_CERTIFICATE_PATH=/my/apply/certificate/path/so/plz/change/it/Certificates.p12
APPLE_CERTIFICATE_PASSWORD=myPassword(plz change it)
KEYSTORE_TYPE=PKCS12
APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME=api.development.push.apple.com
APPLE_NOTIFICATION_PRODUCTION_HOSTNAME=api.push.apple.com
APPLE_NOTIFICATION_PORT=2197
APPLE_APNS_TOPIC=MyAPNS_Topic(plz change it)

您是否找到了导致异常的原因?@risabhRizz plz请检查我的答案,抱歉,我记不起我是如何解决问题的,但我现在粘贴了解决方案。。。检查一下,不要犹豫,问任何问题。祝你好运:)