React Native安卓端SSL固定拦截无响应问题咨询
解决React Native安卓端SSL固定验证失败时无法捕获响应的问题
当SSL固定验证失败时,OkHttp不会返回Response对象,而是直接抛出SSLPeerUnverifiedException异常,这就是你拦截器中chain.proceed(request)之后代码无法执行的核心原因。以下是两种可行的解决方案:
方案一:在拦截器中捕获SSL异常并返回自定义响应
修改CustomInterceptor,通过try-catch精准捕获SSL验证异常,构建包含错误信息的自定义响应,让RN层的Axios可以捕获到:
public class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); System.out.println("My Client::: Intercepted request: " + request.toString()); try { Response res = chain.proceed(request); System.out.println("My Client::: Intercepted response: " + res.toString()); return res; } catch (SSLPeerUnverifiedException sslException) { // 处理SSL固定验证失败场景 System.out.println("SSL Pinning Failed: " + sslException.getMessage()); // 构建自定义错误响应,用非标准状态码(如495)区分SSL错误 return new Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(495) .message("SSL Pinning Verification Failed") .body(ResponseBody.create( MediaType.parse("text/plain"), "SSL Pinning Failed: " + sslException.getMessage() )) .build(); } catch (IOException otherException) { // 其他IO异常直接抛出,交给上层处理 System.out.println("Request Failed: " + otherException.getMessage()); throw otherException; } } }
在RN的Axios中捕获该自定义状态码:
axios.get('/your-api-path') .then(response => { // 正常处理业务响应 }) .catch(error => { if (error.response?.status === 495) { Alert.alert('证书验证失败', '当前网络环境存在安全风险,请检查后重试'); } else { console.error('Request Error:', error); } });
方案二:通过原生事件向RN发送SSL错误通知
如果不想通过响应码传递错误,可以在原生拦截器的异常捕获块中,通过React Native事件发射器向RN层推送错误事件:
1. 原生端修改拦截器
public class CustomInterceptor implements Interceptor { private final ReactApplicationContext reactContext; // 构造方法传入React上下文 public CustomInterceptor(ReactApplicationContext context) { this.reactContext = context; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); System.out.println("My Client::: Intercepted request: " + request.toString()); try { Response res = chain.proceed(request); System.out.println("My Client::: Intercepted response: " + res.toString()); return res; } catch (SSLPeerUnverifiedException sslException) { // 发送SSL错误事件到RN WritableMap errorParams = Arguments.createMap(); errorParams.putString("message", sslException.getMessage()); errorParams.putString("requestUrl", request.url().toString()); reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("onSslPinningFailure", errorParams); // 抛出异常让OkHttp处理,或返回空响应(按需选择) throw sslException; } } }
初始化拦截器时传入ReactApplicationContext:
OkHttpClient.Builder clientBuilder = OkHttpClientProvider.createClientBuilder(); return clientBuilder .certificatePinner(certificatePinner) .addInterceptor(new CustomInterceptor(reactContext)) // 传入上下文 .build();
2. RN端监听事件
import { NativeEventEmitter, Alert, useEffect } from 'react-native'; // 初始化事件发射器 const sslEventEmitter = new NativeEventEmitter(NativeModules.DeviceEventManagerModule); // 监听SSL固定失败事件 const sslFailureSubscription = sslEventEmitter.addListener( 'onSslPinningFailure', (error) => { Alert.alert( '安全验证失败', `请求${error.requestUrl}时SSL证书验证不通过:${error.message}` ); } ); // 组件卸载时取消订阅 useEffect(() => { return () => { sslFailureSubscription.remove(); }; }, []);
注意事项
- 确保添加的是应用拦截器(
addInterceptor)而非网络拦截器(addNetworkInterceptor),应用拦截器会覆盖请求发起前和所有异常场景。 - 自定义状态码尽量选择HTTP标准未使用的范围(如490-499),避免和业务状态码冲突。
内容的提问来源于stack exchange,提问作者Harjinder Singh
相关产品推荐
相关产品推荐

