You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:10:33