使用 SSLContext 时出现 NetworkOnMainThreadException - Android Studio

问题描述 投票:0回答:1

我正在开发一个应连接到网络服务的应用程序。出于开发目的,我使用了简单的 http 协议。这个效果很好。

public Response sendValidRequest(Context context, String encodedAccountData) throws ExecutionException, InterruptedException {

    OkHttpClient client = new OkHttpClient().newBuilder()
            .build();
    RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart(ID, stringParameter)
            .build();
    Request request = new Request.Builder()
            .url(URL)
            .method(POST, body)
            .addHeader(AUTH_HEADER, encodedAccountData)
            .build();
    CompletableFuture<Response> future = new CompletableFuture<>();
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
            future.complete(null);
        }
        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) {
            future.complete(response);
        }
    });
    return future.get();
}

public ValidResponse getValidResponse(Context context, String encodedAccountData) {
    Response response;
    try {
        response = sendValidRequest(context, encodedAccountData);
    } catch (ExecutionException | InterruptedException e) {
        //handle this case
    }

    if(response == null || response.body() == null) {
        //handle this case
    }
    try {
        final String myResponse = response.body().string();
        JSONObject jsonObject = new JSONObject(myResponse);
        //Do something here depending on the content of the response.
    } catch (JSONException | IOException e) {
        //handle this case
    }

然后我为 Web 服务创建了一些证书以便使用 https。 Postman 中的测试(使用 https)工作正常,没有问题。

我添加到清单:

<application android:networkSecurityConfig="@xml/network_security_config">...</application>
Netwok_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="@raw/server_certificate"/>
        </trust-anchors>
    </base-config>
</network-security-config>

还有 server_certificate.crt。

然后我将以下内容添加到代码中:

public Response sendValidRequest(Context context, String encodedAccountData) throws ExecutionException, InterruptedException {
    OkHttpClient client = new OkHttpClient().newBuilder()
        .sslSocketFactory(getSSLSocketFactory(), getTrustManager())
        .hostnameVerifier((hostname, session)->true)
        .build();
        .... //no further changes.

private SSLSocketFactory getSSLSocketFactory() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] {
                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];
                }
            }
        };

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new SecureRandom());

        return sslContext.getSocketFactory();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private X509TrustManager getTrustManager() {
    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];
        }
    };
}

这确实会调用网络服务并返回结果。 但是,我现在在该行中收到 NetworkOnMainThreadException

final String myResponse = response.body().string();
我不知道为什么现在会发生这种情况。使用http的时候没有出现这种情况。当我撤消更改时,异常也消失了。

有人可以向我解释一下为什么我现在遇到异常吗?为什么它可以与 http 请求配合使用?

我尝试寻找答案,但没有成功。

现在我更改了 ThreadPolicy,它有效,但我认为这不是最佳实践。 在类的构造函数中

StrictMode.setThreadPolicy(policy);```

android ssl-certificate okhttp networkonmainthread
1个回答
0
投票

基于 Okhttp 库的文档: https://square.github.io/okhttp/3.x/okhttp/okhttp3/ResponseBody.html

响应正文应在与此指定示例相同的回调中进行管理:

   Call call = client.newCall(request);
   call.enqueue(new Callback() {
     public void onResponse(Call call, Response response) throws IOException {
       try (ResponseBody responseBody = response.body()) {
         ... // Use the response.
       }
     }
     public void onFailure(Call call, IOException e) {
       ... // Handle the failure.
     }
   });

他们提到 如果您在另一个线程上使用响应主体,这些示例将不起作用。,因此请确保响应的管理不是在外部线程上完成的。

最后关于使用 StrictMode 的评论(StrictMode 是一个 开发人员工具,它可以检测您可能意外执行的操作,并引起您的注意,以便您可以修复它们。) 它应该在 DEV 模式下使用意味着您只能将其置于某些开发条件下才能使用,例如

if(DEBUG_MODE) {
  StrictMode.setThreadPolicy(policy)
}
© www.soinside.com 2019 - 2024. All rights reserved.