1. 程式人生 > >java httpclinet請求https地址報java.io.IOException: Invalid keystore format 解決辦法

java httpclinet請求https地址報java.io.IOException: Invalid keystore format 解決辦法

=這又是一次生產問題協查,痛苦的協查。起因是合作方呼叫地址變更,變更後的地址是https協議地址,對方新增了一個.jks的證書庫要載入

程式碼寫完後,一上線發https請求就報錯,因為合作方封裝了一個sdk的包,報錯堆疊資訊沒有向上返回,是返回了一個“加密失敗”,哎。。。。

這裡只能把ssl debug開啟來,開啟方法不太清楚的參考另一篇文章 java ssl除錯開啟ssl debug日誌

開啟後日志看到兩個異常:

java.io.IOException: Invalid keystore format
	at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:650)
	at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
	at java.security.KeyStore.load(KeyStore.java:1445)
	at cfca.httpclient.connector.HttpClient.initSSL(HttpClient.java:77)
	at cfca.httpclient.connector.HttpConnector.init(HttpConnector.java:31)
qtp418304857-24, handling exception: 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
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:1937)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
	at cfca.httpclient.connector.HttpClient.send(HttpClient.java:152)
	at cfca.httpclient.connector.HttpConnector.deal(HttpConnector.java:74)
	at cfca.httpclient.connector.HttpConnector.post(HttpConnector.java:47)

不知道腦子怎麼想的,上來就查第二個異常,花了2天,想了各種辦法,然而沒有解決(路走錯了怎麼能到達終點呢。。。),事實證明,第一個問題解決後,第二個異常也就跟著沒了。查第二個問題看到的一篇文章,雖然沒用到,但是感覺寫的不錯:How to resolve “unable to find valid certification path to requested target” error ? 後面就是加緊解決第一個問題

在網上看到一些處理辦法,說是maven-resources-plugin 在拷貝resources 檔案時進行 encoding  會“誤傷二進位制檔案”導致拷貝到classes下的檔案發生了變化.

我對比了一下,果不其然,對比了下src/main/resources下的jks 檔案和生產執行的classes下的檔案大小不一致,classes目錄下的檔案大了一圈. 嗯,看看別人的處理辦法, filtering=false

    <resources>  
        <resource>  
            <directory>src/main/resources</directory>  
            <filtering>false</filtering>  
        </resource>  
    </resources>  

趕緊去修改自己的pom.xml,開啟自己的pom要修改的時候看到程式碼:

<resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources/certificate</directory>
                <filtering>false</filtering>
            </resource>

        </resources>

 filtering已經是false了,沒毛病,但是還是不行,這是為啥?(certificate目錄下是.jks檔案),看到個別有的文章說配置了filtering=false 沒效,估計跟我這配置應該是差不多的,參考下面的方法:

後來調整了一下配置:

<resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>certificate/*.jks</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>certificate/*.jks</include>
                </includes>
            </resource>
        </resources>

再用maven構建,構建後的.jks檔案大小正常,沒有再變大了!專案部署後,請求https地址也能正常返回了。。。

還看到另外一種配置方式:

<build>
  ...
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-resources-plugin</artifactId>                
      <configuration>
        <nonFilteredFileExtensions>
           <!--這裡是檔案字尾-->
          <nonFilteredFileExtension>jks</nonFilteredFileExtension>
        </nonFilteredFileExtensions>
      </configuration>
    </plugin>
  </plugins>
</build>

因為上面的配置生效了,下面這個方法就沒有嘗試。有興趣的小夥伴可以自己動動手!希望記下的這次處理過程對大家也有幫助!