Android使用OkHttp连接带自签名证书的WebSocket服务器失败
问题解决指南
先搞定域名解析错误(UnknownHostException)
你遇到的java.net.UnknownHostException是Android设备无法解析www.wslphone.com域名导致的,和WSS证书无关——毕竟连服务器地址都找不到,证书验证根本轮不上。
排查&修复步骤:
- 先在Android设备的浏览器里输入
https://www.wslphone.com,如果连证书警告都出不来,直接显示无法访问,说明确实是DNS问题:- 检查设备的DNS设置,切换到公共DNS(比如8.8.8.8或1.1.1.1)试试
- 如果是本地测试的WSL服务器,必须给Android设备添加域名映射:
- 在WSL终端执行
ip addr,找到eth0网卡的inet地址(比如192.168.1.100) - 给Android设备的hosts文件加映射:
- 已root设备:直接编辑
/system/etc/hosts,添加一行192.168.1.100 www.wslphone.com - 未root设备:用adb命令临时添加(需电脑和设备同局域网):
adb shell mount -o rw,remount /system adb shell echo "192.168.1.100 www.wslphone.com" >> /system/etc/hosts adb shell mount -o ro,remount /system
- 已root设备:直接编辑
- 在WSL终端执行
- 验证:修改后再用浏览器访问域名,能弹出证书不安全的警告,就说明解析正常了。
配置OkHttp信任自签名证书(实现WSS连接)
既然你已经有生成keystore.p12的证书,直接把证书导入OkHttp的信任体系即可:
代码实现
- 将你的自签名证书(.crt/.pem格式)放到Android项目的
res/raw目录下 - 编写SSL工具类:
import okhttp3.OkHttpClient; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public class WSSClientUtil { public static OkHttpClient getTrustSelfSignedClient(InputStream certStream) { try { // 加载自签名证书 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(certStream); // 初始化KeyStore KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); keyStore.setCertificateEntry("self-signed-cert", cert); // 构建信任管理器 TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmFactory.init(keyStore); TrustManager[] trustManagers = tmFactory.getTrustManagers(); // 初始化SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagers, null); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); // 构建OkHttpClient return new OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0]) .hostnameVerifier((hostname, session) -> true) // 本地测试可跳过域名验证,正式环境必须移除 .build(); } catch (Exception e) { throw new RuntimeException("Failed to create WSS client", e); } } }
- 发起WSS连接:
// 读取raw目录下的证书 InputStream certInputStream = getResources().openRawResource(R.raw.your_cert_filename); OkHttpClient wssClient = WSSClientUtil.getTrustSelfSignedClient(certInputStream); // 构建WSS请求 Request wssRequest = new Request.Builder() .url("wss://www.wslphone.com:你的WSS端口") .build(); // 建立WebSocket连接 wssClient.newWebSocket(wssRequest, new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { // 连接成功,可发送消息 webSocket.send("Hello WSS!"); } @Override public void onMessage(WebSocket webSocket, String text) { // 接收服务器消息 } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { // 连接失败,打印错误信息 t.printStackTrace(); } });
关键注意事项
- 正式环境绝对不能跳过hostname验证,必须确保证书的CN字段或SAN扩展和你的域名完全匹配
- 如果是WSL服务器,要确保WSL防火墙开放了WSS端口(比如
ufw allow 8443),且设备和WSL在同一局域网(或做了端口映射) - 你已经能用wscat连接,说明服务器的WSS配置没问题,只要搞定Android端的域名解析和证书信任即可
内容的提问来源于stack exchange,提问作者Jaydeep Kasture
相关产品推荐
相关产品推荐

