WEB/Web

[APNs] 애플 푸쉬 서비스 개발 도중 오류 해결 (jdk8, http2, java.io.IOException: unexpected end of stream on Connection, HTTP/2 is disabled. Is alpn-boot on the boot class path?)

염소 2021. 11. 9. 22:11
반응형

1. 배경

- 회사 모바일푸시 서비스는 FCM토큰방식으로 푸쉬를 발송함.

- 중국 사용자가 google도메인이 막혀 FCM토큰 값을 가져올 수 없는 상황 발생.

- 아이폰 사용자를 위한 APNs푸쉬 서비스를 따로 개발하기로 함.

 

2. 개발 스택

- spring + apache/tomcat8.5

- 사용 라이브러리 apns-httpd2

GitHub - CleverTap/apns-http2: A Java library for sending notifications via APNS using Apple's HTTP/2 API.

 

GitHub - CleverTap/apns-http2: A Java library for sending notifications via APNS using Apple's HTTP/2 API.

A Java library for sending notifications via APNS using Apple's HTTP/2 API. - GitHub - CleverTap/apns-http2: A Java library for sending notifications via APNS using Apple's HTTP/2 API.

github.com

 

 

3. 오류 발생 배경

- 라이브러리에서 제공하는 비동기 방식으로 처리 후 로컬에서 발송 시 제대로 발송되는 것을 확인하고 개발서버에 반영.

- 개발서버에서 푸쉬가 발송되지 않는 현상 발생.

에러 로그는 아래와 같았다.

APNS FAIL : token : E4DADD3C7D83145C5EDF4B93137A8B8D9AEC2F1F280735128724C4188ADEB65E  NotificationResponse{error=null, httpStatusCode=-1, responseBody='null', cause=java.io.IOException: unexpected end of stream on Connection{api.push.apple.com:443, proxy=DIRECT hostAddress=api.push.apple.com/17.188.138.185:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 protocol=http/1.1}}
java.io.IOException: unexpected end of stream on Connection{api.push.apple.com:443, proxy=DIRECT hostAddress=api.push.apple.com/17.188.138.185:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 protocol=http/1.1}
        at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:205)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:125)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.EOFException: \n not found: limit=159 content=000018040000000000000100001000000300000001000500004000000600001f…
        at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:227)
        at okhttp3.internal.http1.Http1Codec.readHeaderLine(Http1Codec.java:212)
        at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:189)
        ... 19 more

 

????

 

4. 오류 해결

- 바로 github issue가서 같은 오류가 난 사용자가 있나 찾아봤다.

라이브러리 설명을 제대로 읽지 않았다.

APNs는 HTTP2를 사용하기 때문에 HTTP2 가지원되어야 한다.

 

jdk8을 사용하기 때문에 http2를 지원하지 않아 jetty라이브러리가 추가로 필요했던 것.

java 버전을 올리는 것 보다 일단 http2를 사용하게 해주는 ALPN을 추가하기로 함.

 

1) maven을 사용했기에 pom에 의존성을 추가했다.

<dependency>
 <groupId>org.mortbay.jetty.alpn</groupId>
 <artifactId>alpn-boot</artifactId>
 <version>8.1.12.v20180117</version>
</dependency>

자신의 jdk 버전과 맞는 버전은 아래의 url참고.

https://github.com/jetty-project/jetty-alpn/blob/master/docs/version_mapping.properties

 

GitHub - jetty-project/jetty-alpn: Implementation of ALPN (Application Layer Protocol Negotiation) Specification for OpenJDK 7 o

Implementation of ALPN (Application Layer Protocol Negotiation) Specification for OpenJDK 7 or greater - GitHub - jetty-project/jetty-alpn: Implementation of ALPN (Application Layer Protocol Negoti...

github.com

 

2) java실행 구문에 아래와 같은 jvm옵션 추가.

-Xbootclasspath/p:{/mobilePush/WEB-INF/lib/alpn-boot-8.1.12.v20180117.jar}

({}안은 jar파일의 절대경로 추가.)

 

이러고 서비스를 재시작하면 APNs푸쉬가 제대로 가는 것을 확인할 수 있다.(포트는 기본 443이므로 열려있어야 함.)

 

 

+ 추가사항

- 라이브러리를 추가했는데도 아래와 같은 오류가 날 수도 있음.

org.apache.http.impl.conn.PoolingHttpClientConnectionManager [DEBUG] Connection manager shut down
09-Nov-2021 11:05:42.775 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:43.817 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:44.862 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:45.904 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:46.944 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:47.988 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:49.012 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
09-Nov-2021 11:05:50.051 INFO [OkHttp https://api.push.apple.com/...] okhttp3.internal.platform.Platform.log ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?

 

침착하게 

1. jdk버전과 ALPN버전이 맞나 확인

2. jvm옵션을 제대로 적용했는지 확인

 

하면 된다.

 

끝.

반응형