Android调用ejabberd REST API发消息报错:POSTMAN正常OKHTTP异常
我帮你分析了下你的ejabberd配置和Android代码,发现几个关键问题导致调用失败,逐个给你说清楚怎么解决:
1. 协议不匹配:HTTP vs HTTPS
你的ejabberd配置里,5443端口明确开启了tls: true,这意味着这个端口只接受HTTPS请求,但你的Android代码里用的是http://192.168.1.24:5443/api/send_message,直接用HTTP访问HTTPS端口肯定会触发连接异常——Postman能正常工作应该是你手动改成了HTTPS但没注意到。
解决方法:把请求URL改成https://192.168.1.24:5443/api/send_message
2. 请求体格式与Content-Type不匹配
你代码里设置了content-type: application/json,但用的是FormBody(这对应application/x-www-form-urlencoded格式),ejabberd的REST API要求JSON格式的请求体,服务器无法解析这种不匹配的请求,会直接断开连接。
解决方法:改用JSON字符串作为请求体,示例代码如下:
String jsonBody = "{\n" + " \"type\": \"normal\",\n" + " \"from\": \"admin@faiqkhan-VirtualBox\",\n" + " \"to\": \"faiq@faiqkhan-VirtualBox\",\n" + " \"subject\": \"\",\n" + " \"body\": \"In 5 minutes\"\n" + "}"; RequestBody requestBody = RequestBody.create( jsonBody, MediaType.parse("application/json; charset=utf-8") );
3. 缺少API认证信息
ejabberd的mod_http_api需要认证才能调用,Postman里你应该是配置了Basic Auth或者OAuth凭证,但Android代码里完全没加认证头,服务器会直接拒绝请求,导致连接异常。
解决方法:添加Basic认证头,替换成你的管理员账号和密码:
String credentials = "admin@faiqkhan-VirtualBox:你的管理员密码"; String base64Credentials = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); String authHeader = "Basic " + base64Credentials; // 在Request.Builder中添加这个头 .addHeader("Authorization", authHeader)
4. 忽略自签名证书(测试环境专属)
因为你用的是自己生成的server.pem证书,Android默认会不信任这类自签名证书,导致SSL握手失败。测试环境下可以临时忽略证书验证(生产环境绝对不要这么做,应该导入合法证书):
// 构建OkHttpClient时添加证书忽略逻辑 OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(createInsecureSSLSocketFactory(), createTrustAllManager()) .hostnameVerifier((hostname, session) -> true) .build(); // 辅助方法:创建不安全的SSL工厂 private SSLSocketFactory createInsecureSSLSocketFactory() { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{createTrustAllManager()}, new SecureRandom()); return sslContext.getSocketFactory(); } catch (Exception e) { throw new RuntimeException(e); } } // 辅助方法:信任所有证书的管理器 private X509TrustManager createTrustAllManager() { return new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }; }
整理后的完整代码片段
OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(createInsecureSSLSocketFactory(), createTrustAllManager()) .hostnameVerifier((hostname, session) -> true) .build(); String jsonBody = "{\n" + " \"type\": \"normal\",\n" + " \"from\": \"admin@faiqkhan-VirtualBox\",\n" + " \"to\": \"faiq@faiqkhan-VirtualBox\",\n" + " \"subject\": \"\",\n" + " \"body\": \"In 5 minutes\"\n" + "}"; RequestBody requestBody = RequestBody.create( jsonBody, MediaType.parse("application/json; charset=utf-8") ); String credentials = "admin@faiqkhan-VirtualBox:你的管理员密码"; String base64Credentials = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); String authHeader = "Basic " + base64Credentials; Request request = new Request.Builder() .url("https://192.168.1.24:5443/api/send_message") .addHeader("content-type", "application/json") .addHeader("Authorization", authHeader) .post(requestBody) .build(); try { Response response = client.newCall(request).execute(); // 这里可以添加响应处理逻辑,比如打印response.body().string() } catch (IOException e) { e.printStackTrace(); } // 别忘了添加这两个辅助方法 private SSLSocketFactory createInsecureSSLSocketFactory() { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{createTrustAllManager()}, new SecureRandom()); return sslContext.getSocketFactory(); } catch (Exception e) { throw new RuntimeException(e); } } private X509TrustManager createTrustAllManager() { return new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }; }
另外补充一下:你的api_permissions配置已经允许管理员和本地环回地址调用所有API,只要认证信息正确,权限方面是没问题的。
内容的提问来源于stack exchange,提问作者FaaiqKhan

