【问题标题】:ClassNotFoundException on org.apache.http.ssl.TrustStrategyorg.apache.http.ssl.TrustStrategy 上的 ClassNotFoundException
【发布时间】:2017-06-25 20:04:57
【问题描述】:

我正在尝试运行一个发出 HTTP/HTTPS POST 请求的插件。在它上面声明了所需的依赖关系,即httpclienthttpcore。我分别使用版本 4.5.3 和 4.4.6。虽然全部正确导入(我的意思是),但我在执行时收到了这个错误:

Caused by: java.lang.NoClassDefFoundError: 
org/apache/http/ssl/TrustStrategy
25.06 19:59:12 [Server] INFO at 
com.b5team.postrequest.Main.onCommand(Main.java:77) ~[?:?]
25.06 19:59:12 [Server] INFO at 
org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~
[Spigot.jar:git-Spigot-3fb9445-6e3cec8]
25.06 19:59:12 [Server] INFO ... 10 more
25.06 19:59:12 [Server] INFO Caused by: 
java.lang.ClassNotFoundException: org.apache.http.ssl.TrustStrategy

这是我的代码:

package com.b5team.postrequest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

public class SocketPOSTRequest {

    public void sendRequest(String myurl, String hash, String args[]) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, ClientProtocolException, IOException {

        HttpClientBuilder b = HttpClientBuilder.create();

        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                return true;
            }
        }).build();

        b.setSSLContext(sslContext);

        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;

        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslSocketFactory)
                .build();

        PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        b.setConnectionManager(connMgr);

        HttpClient client = b.build();
        HttpPost post = new HttpPost(myurl);

        List<NameValuePair> params = new ArrayList<NameValuePair>(args.length);
        params.add(new BasicNameValuePair("hash", hash));

        for(int i = 0; i < args.length; i++) {
            params.add(new BasicNameValuePair("arg"+i, args[i]));
        }

        post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
        HttpResponse response = client.execute(post);
        HttpEntity entity = response.getEntity();

        if (entity != null) {

            InputStream in = entity.getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;

            System.out.println("[POSTRequest] Data sent successfully!");

            while ((line = reader.readLine()) != null) {
                System.out.println("[POSTRequest] Report: "+line);
            }
        }
    }
}

编辑: 我使用 Ant 构建,并且正确添加了依赖项。我也用 Maven 进行了测试,添加了依赖项,但错误仍然存​​在。

EDIT2: 切换到 Maven,添加了 maven-shade-plugin 和 maven-compile-plugin。错误消失了,但现在得到了这个java.lang.NoSuchMethodError: org.apache.http.impl.client.HttpClientBuilder.setSSLContext。使用 junit 运行时,不会出现任何错误。它仅在服务器上运行时发生,即 Spigot 1.11.2 Minecraft 服务器。

【问题讨论】:

    标签: java httpclient apache-httpclient-4.x minecraft bukkit


    【解决方案1】:

    如果您使用的是 maven 项目,请在您的 pom.xml 文件中添加以下依赖项。

     <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
    </dependency>
    

    【讨论】:

    • 所以,我正在使用 Ant,但是在尝试使用 Maven 时,错误仍然存​​在。
    • 你使用的是哪个版本的httpclient?
    • httpclient 4.5.3 和 httpcore 4.4.6
    • 请你用httpclient 4.5.2和httpcore 4.4测试一下
    • 错误仍然存​​在。
    【解决方案2】:

    所以,我用 javax sslcontext 方法替换了 apache httpclient 和 httpcore 中的 sslcontext 方法。现在,一切正常。请记住,上面的代码在纯 java 上正常工作。真正的问题是在 Minecraft 服务器上运行时。

    不管怎样,我会把新代码放在下面,作为文档,也许对某人有帮助。

    package com.b5team.postrequest;
    
    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.UnsupportedEncodingException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    public class HttpsPOSTRequest {
    
        public static void sendRequest(String myurl, String hash, String args[]) throws NoSuchAlgorithmException, KeyManagementException {
    
            try {
                SSLContext context = SSLContext.getInstance("TLS");
                context.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
                SSLContext.setDefault(context);
    
                URL url = new URL(myurl);
                HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
                con.setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String arg0, SSLSession arg1) {
                        return true;
                    }
                });
    
                con.setRequestMethod("POST");
                con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
                con.setDoOutput(true);
                con.setDoInput(true);
    
                ArrayList<String> params = new ArrayList<String>(args.length + 1);
    
                DataOutputStream output = new DataOutputStream(con.getOutputStream());
                output.writeBytes("hash=" + hash);
                for(int i = 0; i < params.size(); i++) {
                    output.writeBytes("&");
                    output.writeBytes("arg" + i + "=" + args[i]);
                    output.flush();
                }
    
                output.flush();
                output.close();
    
                DataInputStream input = new DataInputStream(con.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(input));
                String line;
    
                System.out.println("[POSTRequest] Data sent successfully!");
                System.out.println("[POSTRequest] Resp Code:"+con.getResponseCode());
                System.out.println("[POSTRequest] Resp Message:"+con.getResponseMessage());
    
                while ((line = reader.readLine()) != null) {
                    System.out.println("[POSTRequest] Report: "+line);
                }
    
                input.close();
    
            } catch (UnsupportedEncodingException e) {
                System.out.println("[POSTRequest] Encoding error. Maybe string have invalid caracters.");
                e.printStackTrace();
            } catch (MalformedURLException e) {
                System.out.println("[POSTRequest] Invalid URL. Verify your URL and try again.");
                e.printStackTrace();
            } catch (IOException e) {
                System.out.println("[POSTRequest] Error on HTTPS connection.");
                e.printStackTrace();
            }
        }
    
        private static class DefaultTrustManager implements X509TrustManager {
    
            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
    
            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
    
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }
    }
    

    【讨论】:

    • 还有其他解决方法可以解决这个问题吗?我使用 maven,httpclient 4.5.3 和 httpcore 4.4.6 + java 8
    • 一切都取决于 maven 文件的正确配置。一段时间后,由于 maven 上的着色器方法,我得到了 apache httpclient 工作。
    • 我猜你的意思是 JAR 着色?我认为您的问题是依赖项的错误设置。也许你最终得到了一个错误的设置,它是偶然的。例如。它在 JUnit 中工作,因为测试依赖项包含 lib,但它不包含在 Minecraft 服务器的类路径中。解决此问题的方法是 1) 检查完整的依赖关系树,包括范围。 2) 找出具有所有运行时依赖项的 .jar。 3) 将这些 jars 添加到服务器的类路径中。 3b) 或者,您可以创建一个带阴影的 jar 来将您的插件作为一个存档分发,但这可能会带来问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 2023-03-21
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    相关资源
    最近更新 更多