You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java连接要求Explicit FTP over TLS的FTP服务器时SSL握手异常求助

Fixing SSLHandshakeException for Explicit FTP over TLS with Commons Net 3.6 (Java 8)

Hey Jon, sorry to hear you're hitting this frustrating handshake error—especially since FileZilla works perfectly, we know the server is configured correctly. Let's walk through the most common fixes for this issue with Apache Commons Net 3.6 in Java 8:

1. Ensure You're Using Explicit FTPS Mode Correctly

First, make sure your FTPSClient is initialized for explicit TLS (the mode your server requires). Unlike implicit FTPS (which uses port 990 by default), explicit starts with a regular FTP connection on port 21, then upgrades to TLS via the AUTH TLS command.

Here's the correct initialization code:

FTPSClient ftpsClient = new FTPSClient("TLS", false); // false = explicit mode

2. Force TLS 1.2 (Java 8's Default May Be Too Old)

Java 8 defaults to enabling TLS 1.0, 1.1, and 1.2, but many modern FTPS servers disable the older, insecure TLS versions. FileZilla automatically negotiates the highest supported version, but Java might get stuck trying an outdated one.

Add this code to force TLS 1.2 before connecting:

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

try {
    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(null, null, null);
    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    ftpsClient.setSocketFactory(sslSocketFactory);
} catch (Exception e) {
    e.printStackTrace();
}

3. Enable Passive Mode (Match FileZilla's Behavior)

FileZilla uses passive mode by default, but Commons Net's FTPSClient might not. If you're in active mode, the server could refuse the connection or drop the handshake. Enable passive mode with:

ftpsClient.enterLocalPassiveMode();

4. Protect Data Connections with execPROT

Many explicit FTPS servers require data connections (for file uploads/downloads) to also be encrypted. If you skip this step, the server might close the connection mid-handshake. Add this right after logging in:

ftpsClient.execPROT("P"); // "P" = protect data connection

5. Fix Certificate Trust Issues

If your server uses a self-signed certificate or one from a non-public CA, Java's default truststore won't recognize it—unlike FileZilla, which prompts you to trust unknown certificates.

Create a trust manager that accepts all certificates:

import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

public class TrustAllCertManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
    @Override
    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
    @Override
    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}

Then update your SSLContext initialization to use this trust manager:

SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, new javax.net.ssl.TrustManager[]{new TrustAllCertManager()}, new java.security.SecureRandom());

You might also need to disable hostname verification if the certificate's CN doesn't match the server's hostname:

ftpsClient.setHostnameVerifier((hostname, session) -> true);

For Production:

Import the server's certificate into Java's cacerts truststore using the keytool command. This is the secure, recommended approach.

Full Working Example

Here's putting it all together for a file upload:

import org.apache.commons.net.ftp.FTPSClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileInputStream;
import java.io.IOException;

public class FtpUploader {
    public static void main(String[] args) {
        FTPSClient ftpsClient = new FTPSClient("TLS", false);
        String server = "your-ftp-server.com";
        int port = 21;
        String user = "your-username";
        String pass = "your-password";
        String localFilePath = "/path/to/local/file.txt";
        String remoteFilePath = "/path/on/server/file.txt";

        try {
            // Force TLS 1.2
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, new javax.net.ssl.TrustManager[]{new TrustAllCertManager()}, new java.security.SecureRandom());
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            ftpsClient.setSocketFactory(sslSocketFactory);
            ftpsClient.setHostnameVerifier((hostname, session) -> true);

            // Passive mode
            ftpsClient.enterLocalPassiveMode();

            // Connect and login
            ftpsClient.connect(server, port);
            ftpsClient.login(user, pass);

            // Protect data connection
            ftpsClient.execPROT("P");

            // Set file type to binary
            ftpsClient.setFileType(FTPSClient.BINARY_FILE_TYPE);

            // Upload file
            try (FileInputStream fis = new FileInputStream(localFilePath)) {
                boolean uploaded = ftpsClient.storeFile(remoteFilePath, fis);
                if (uploaded) {
                    System.out.println("File uploaded successfully!");
                } else {
                    System.out.println("File upload failed: " + ftpsClient.getReplyString());
                }
            }

            // Logout and disconnect
            ftpsClient.logout();
            ftpsClient.disconnect();
        } catch (IOException | java.security.GeneralSecurityException e) {
            e.printStackTrace();
        }
    }
}

Try these steps one by one—most likely, the TLS version or data connection protection is the culprit. Let me know if you still run into issues!

内容的提问来源于stack exchange,提问作者Louie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:35:29