2013-09-02 3 views
0

J'essaie d'enregistrer un fichier à partir d'une URL en utilisant outputtream. L'URL est sécurisée par https. Je suis une erreur lorsque je tente d'obtenir le fichier comme suitComment enregistrer le fichier depuis l'URL HTTPS dans JAVA?

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(Unknown Source) 
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) 
at sun.security.ssl.Handshaker.fatalSE(Unknown Source) 
at sun.security.ssl.Handshaker.fatalSE(Unknown Source) 
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source) 
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) 
at java.net.URL.openStream(Unknown Source) 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) 
    at java.security.cert.CertPathBuilder.build(Unknown Source) 
    ... 60 more 

Supposons que je veux ouvrir le fichier à partir de cette URL

https://www.filepicker.io/api/file/KW9EJhYtS6y48Whm2S6D?signature=4098f262b9dba23e4766ce127353aaf4f37fde0fd726d164d944e031fd862c18&policy=eyJoYW5kbGUiOiJLVzlFSmhZdFM2eTQ4V2htMlM2RCIsImV4cGlyeSI6MTUwODE0MTUwNH0= 

donc je fais quelque chose comme:

try{  
    URL URL = new URL('https://www.filepicker.io/api/file/KW9EJhYtS6y48Whm2S6D?signature=4098f262b9dba23e4766ce127353aaf4f37fde0fd726d164d944e031fd862c18&policy=eyJoYW5kbGUiOiJLVzlFSmhZdFM2eTQ4V2htMlM2RCIsImV4cGlyeSI6MTUwODE0MTUwNH0='); 
    String = path = "D://download/"; 
    InputStream ins = url.openStream(); 
    OutputStream ous = new FileOutputStream(path); 
    final byte[] b = new byte[2048]; 
    int length; 

     while ((length = inputStream.read(b)) != -1) { 
       ous.write(b, 0, length); 
     } 

      ins.close(); 
      ous.close(); 
} 

Le résultat est que rien ne se passe dans le floder dédié car l'erreur est visible. Comment puis-je obtenir le fichier à partir de l'URL HTTPS?

Répondre

8

Une connexion HTTPS nécessite un établissement de liaison. C'est à dire. reconnaître explicitement les uns les autres. Le serveur s'est identifié par un certificat HTTPS, mais vous n'avez apparemment pas ce certificat dans votre magasin de confiance et vous n'êtes nulle part dans votre code Java reconnaissant explicitement l'identification, donc le HttpsURLConnection (qui est utilisé sous les couvertures ici) refuse pour continuer la requête HTTPS.

Comme exemple de démarrage, vous pouvez utiliser le code suivant dans votre classe pour permettre à HttpsURLConnection d'accepter tous les certificats SSL, quelle que soit l'URL HTTPS que vous utilisez.

static { 
    final TrustManager[] trustAllCertificates = new TrustManager[] { 
     new X509TrustManager() { 
      @Override 
      public X509Certificate[] getAcceptedIssuers() { 
       return null; // Not relevant. 
      } 
      @Override 
      public void checkClientTrusted(X509Certificate[] certs, String authType) { 
       // Do nothing. Just allow them all. 
      } 
      @Override 
      public void checkServerTrusted(X509Certificate[] certs, String authType) { 
       // Do nothing. Just allow them all. 
      } 
     } 
    }; 

    try { 
     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCertificates, new SecureRandom()); 
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
    } catch (GeneralSecurityException e) { 
     throw new ExceptionInInitializerError(e); 
    } 
} 

Si vous voulez cependant plus un contrôle précis à grains sur une base par certificat, puis mettre en œuvre les méthodes en conséquence que par their Javadoc.


au Unrelated problème concret, vous avez un deuxième problème dans votre code. Vous essayez de le sauvegarder en tant que dossier plutôt qu'en tant que fichier.

String = path = "D://download/"; 
OutputStream ous = new FileOutputStream(path); 

En dehors de l'erreur de syntaxe qui est plus probable de résultat négligence lors de la formulation de la question (à savoir modifier le code en question directement au lieu du code de travail copypasting en fait), ce ne fait aucun sens. Vous ne devez pas spécifier un dossier comme emplacement de sauvegarde. Vous devez spécifier un nom de fichier. Vous pouvez, si nécessaire, l'extraire de l'en-tête Content-Disposition ou en générer automatiquement un avec File#createTempFile(). Par exemple.

File file = File.createTempFile("test-", ".jpg", new File("D:/download/")); 
Files.copy(url.openStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); 

(et si vous êtes déjà en Java 7, juste utiliser Files#copy() au lieu de ce passe-partout)

+0

Merci beaucoup pour votre réponse, @BalusC. J'ai une question sur le certificat SSL. Ici, vous m'avez dit que le code accepterait tous les certificats SSL. Cela signifie qu'il fera confiance au faux certificat ou au certificat non vérifié, n'est-ce pas? Merci encore pour votre suggestion supplémentaire sur l'autre problème dans mon code. – Takumi

+1

C'est correct. – BalusC

+0

Je voudrais demander une information supplémentaire, @BalusC Si je veux faire confiance seulement le certificat spécifique. Pourriez-vous s'il vous plaît me suggérer comment faire cela? – Takumi

0

La cause de l'erreur est que Java ne peut pas confirmer la validité du certificat. Ceci peut être corrigé en important le certificat dans le stockage de certificat JAVA, ou "fixé" en désactivant la validation du certificat SSL.

Questions connexes