React Native系列(5) - OkHttp中HTTP2的坑
欢迎转载,请支持原创,保留原文链接:blog.ilibrary.me
OkHttp3 中HTTP2的crash
React-native android app发PUT/POST请求给nginx HTTP2 服务器时会crash.
在React Native 0.38中遇到一个发送PUT和POST请求会crash的问题,程序启动一段时间之后搁置几分钟不用,然后再发PUT或者POST就会crash,OkHttp抛下面的错误,后来查明是服务器开启了http2导致了,禁用http2问题就消失了。
java.lang.IllegalStateException: closed
at okio.RealBufferedSink.write(RealBufferedSink.java:39)
at okio.ForwardingSink.write(ForwardingSink.java:35)
at com.facebook.react.modules.network.ProgressRequestBody$1.write(ProgressRequestBody.java:58)
at okio.RealBufferedSink.flush(RealBufferedSink.java:216)
at com.facebook.react.modules.network.ProgressRequestBody.writeTo(ProgressRequestBody.java:48)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:47)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:109)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:124)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:170)
at okhttp3.RealCall.access$100(RealCall.java:33)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:120)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
解决方法,在React-Native里面禁用HTTP2
方法1. 禁用HTTP2有非常简单的方法, 直接在android启动的时候替换掉httpClient
// 把下面的代码插入MainApplication.java的 protected List<ReactPackage> getPackages() { 方法的第一行, 放其它地方可能会有时序的问题导致替换失败。
List<Protocol> protocolList = new ArrayList<>();
protocolList.add(Protocol.SPDY_3);
protocolList.add(Protocol.HTTP_1_1);
OkHttpClient client = OkHttpClientProvider.getOkHttpClient();
OkHttpClient.Builder clientBuilder = client.newBuilder();
clientBuilder = clientBuilder.protocols(protocolList);
client = clientBuilder.build();
OkHttpClientProvider.replaceOkHttpClient(client)
方法2,该解决方案总共分两步
(注意,该方法太复杂了,还得自己编译私有react native代码,建议用上面的方法
)
1. 禁用HTTP2
Fork自己的分支,然后修改文件
node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
,
改动如下:
import java.util.ArrayList;
import okhttp3.Protocol;
...
if (networkInterceptorCreators != null) {
OkHttpClient.Builder clientBuilder = client.newBuilder();
for (NetworkInterceptorCreator networkInterceptorCreator : networkInterceptorCreators) {
clientBuilder.addNetworkInterceptor(networkInterceptorCreator.create());
}
client = clientBuilder.build();
}
// filter http2
List<Protocol> protocolList = new ArrayList<>();
protocolList.add(Protocol.SPDY_3);
protocolList.add(Protocol.HTTP_1_1);
OkHttpClient.Builder clientBuilder = client.newBuilder();
clientBuilder = clientBuilder.protocols(protocolList);
client = clientBuilder.build();
...
2. 自己编译React-Native代码
把自己fork的react-native作为依赖替换原有的react-native,然后编译。
编译过程比较麻烦,中间有一些坑。详情请参见本博客另外一篇文章,编译私有React-Native代码
我有提交一个私有版本的修复
我有fork并修复这个问题,如果你不想自己去维护一个分支,可以直接运行下面的命令来切换到我的私有版本。该修复只在0.40-stable上存在。
npm install --save github:younthu/react-native#0.40-stable