java - 必应 Azure 搜索 API

标签 java ssl ssl-certificate bing-api

我正在尝试连接到必应搜索 API,但未能使代码正常工作。我已经用 Google 搜索了这个问题,但没有找到有效的代码。

这是我的代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.codec.binary.Base64;


public class BSearch{
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //--------------------------------------Bing search------------------------------
        String searchText = "barack";
        searchText = searchText.replaceAll(" ", "%20");
        String accountKey="MYACCOUNTKEY";
        byte[] accountKeyBytes = Base64.encodeBase64((accountKey + ":" + accountKey).getBytes());
        String accountKeyEnc = new String(accountKeyBytes);
        URL url;
        try {
            url = new URL(
                    "https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1/Web?Query=%27" + searchText + "%27&$top=50&$format=json");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Authorization", "Basic " + accountKeyEnc);

     //  conn.setRequestProperty("Accept", "application/json");

        BufferedReader br = new BufferedReader(new InputStreamReader(
                (conn.getInputStream())));
        StringBuilder sb = new StringBuilder();
        String output;
        System.out.println("Output from Server .... \n");
        while ((output = br.readLine()) != null) {
            sb.append(output);

            System.out.println(output);
        }

        conn.disconnect();
        } catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }
}

这会导致以下错误:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1886)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:515)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1299)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at BSearch.main(BSearch.java:30)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
    ... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 18 more

谢谢。

最佳答案

您的 Java 客户端需要 Bing 的服务器公共(public)证书才能开始通信(SSLHandshake),您收到错误是因为 Bing 的证书不在您的默认 Java keystore 中作为受信任的证书。

您可以执行以下操作:

  • 获取 Bing 的证书并使用 keytool 导入到您的默认 Java keystore 以获得受信任的证书,您的名为 cacerts 的默认 keystore 通常位于 JAVA_HOME\jre\lib\security\

keytool -importcert -file bingcertificate.cer -keystore cacerts -alias "bingAlias"

  • 创建一个虚拟的 SSLSocketFactory 来获取一个 SSLContext,它接受任何证书并将其与您的 http 连接对象一起使用。

工厂示例:

public class DummySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public DummySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                //
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                //
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

然后

HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(new DummySSLSocketFactory());
  • 创建您自己的 keystore ,导入证书并将其加载到您的代码中以获取新工厂

keystore 示例:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream(new File("keystoreCompletePath")), "passwdKeyStore");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory sslFactory = ctx.getSocketFactory();

然后

HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslFactory);

关于java - 必应 Azure 搜索 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20706026/

相关文章:

java - 显示 java 文件上的 swt 选项卡

java - 提取列表中给定数量的最大值

java - 按当前月份排序 List<Object> 到最近六个月

使用 digicert 在服务器中更新证书后出现 Android ssl 证书错误

testing - 如何关闭特定站点的 Postman 上的所有 SSL 检查?

java - 错误: reached end of file while parsing

php - curl 错误 : [35] Unsupported SSL protocol version

python - 我需要为带有 SSL 套接字连接的 Python 分发什么( key 、证书)?

ssl - 未找到 BizTalk WCF-WebHttp 适配器客户端证书

php - Authorize.net ARB SSL 证书问题