Java FTP 客户端失败,显示“425 无法建立连接”
Java FTP client failing with "425 Failed to establish connection"
当我尝试在 ftp 服务器上上传文件时,我的 FtpClient
class 出现错误。我收到此消息:
220 (vsFTPd 3.0.3)
USER newftpuser
331 Please specify the password.
PASS ftp
230 Login successful.
TYPE I
200 Switching to Binary mode.
PORT 192,168,1,7,235,73
200 PORT command successful. Consider using PASV.
STOR /upload/logo.png
425 Failed to establish connection.
FtpClient.java
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
public class FtpClient {
private String server;
private int port;
private String user;
private String password;
private FTPClient ftp;
public void open() throws IOException {
ftp = new FTPClient();
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
ftp.enterLocalPassiveMode();
ftp.connect(server, port);
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
throw new IOException("Exception in connecting to FTP Server");
}
ftp.login(user, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
}
public void close() throws IOException {
ftp.disconnect();
}
public void putFileToPath(InputStream inputStream, String path) throws IOException {
ftp.storeFile(path, inputStream);
}
}
测试
@Test
public void dropFileOnFtpServer() throws IOException, URISyntaxException {
ftpClient = new FtpClient(...);
ftpClient.open();
InputStream inputStream = this.getClass().getResourceAsStream("/images/logo.png");
ftpClient.putFileToPath(inputStream, "/upload/logo.png");
assertTrue(ftpClient.listFiles("/upload").contains("logo.png"));
ftpClient.close();
}
已解决
问题的原因是被动模式。 appache.commons.net 的 FTPClient 在下载或上传文件之前需要手动启用被动模式,因此程序无法正常运行。
解决方案
public void putFileToPath(InputStream inputStream, String path) throws IOException {
ftp.enterLocalPassiveMode();
/* I enable this mode before connecting ftp, so client doesnt work*/
ftp.storeFile(path, inputStream);
}
请检查 Android FTP error - 425 Can't open data connection and Error: 425 Can't open data connection 并根据这些指南编辑您的配置。
我正在使用这个 class 进行 ftp 处理,您可以实现自己的异常处理和配置管理。
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPSClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
@Component
@Slf4j
public class FTPFileWriterImpl implements FTPFileWriter {
private final FTPProperties ftpProperties;
protected FTPClient ftpClient;
@Autowired
public FTPFileWriterImpl(@Autowired FTPProperties ftpProperties) {
this.ftpProperties = ftpProperties;
}
//@PostConstruct
public void init() {
if (this.ftpProperties.isAutoStart()) {
log.debug("Autostarting connection to FTP server.");
this.open();
}
}
public boolean open() {
close();
log.debug("Connecting and logging in to FTP server.");
if (ftpProperties.getProtocolType().equals("SSL"))
ftpClient = new FTPSClient();
else
ftpClient = new FTPClient();
ftpClient.enterLocalPassiveMode();
boolean loggedIn = false;
try {
ftpClient.connect(ftpProperties.getServer(), ftpProperties.getPort());
loggedIn = ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword());
if (loggedIn) {
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
if (ftpProperties.getKeepAliveTimout() > 0)
ftpClient.setControlKeepAliveTimeout(ftpProperties.getKeepAliveTimout());
} else {
log.error("Failed login to FTP server");
ftpClient.logout();
ftpClient.disconnect();
}
} catch (Exception e) {
log.error(e.getMessage());
}
return loggedIn;
}
public void close() {
if (ftpClient != null) {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
public InputStream loadFile(String fileName) {
try {
log.debug("Trying to retrieve a file from remote path " + fileName);
this.open();
return ftpClient.retrieveFileStream(fileName);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new StorageFileNotFoundException("File not found!");
} finally {
this.close();
}
}
public boolean delete(String fileName) throws IOException {
this.open();
boolean result = ftpClient.deleteFile(fileName);
this.close();
return result;
}
public String saveFile(InputStream inputStream, String dir, String fileName, boolean append) throws Exception {
log.debug("Trying to store a file to destination path " + fileName);
boolean result;
this.open();
try {
String saveDir = this.ftpProperties.getRemoteDir() + "/" + dir;
if (!directoryExists(saveDir)) {
boolean makeDirResult = this.ftpClient.makeDirectory(saveDir);
if(!makeDirResult) {
log.error("Storage directory {} does not exist on ftp server, failed to create it!", saveDir);
throw new StorageException("Storage directory {} does not exist on ftp server, failed to create it!");
}
}
String remote = saveDir + "/" + fileName;
if (append)
result = ftpClient.appendFile(remote, inputStream);
else
result = ftpClient.storeFile(remote, inputStream);
if (!result) {
log.error("Cannot save file on server, Server response is: {}", ftpClient.getReplyCode());
throw new StorageException(String.format("Cannot save file on server: %s", ftpClient.getReplyCode()));
}
return remote;
}
finally {
this.close();
}
}
public String saveFile(String sourcePath, String fileName, boolean append) throws Exception {
InputStream inputStream;
inputStream = new ClassPathResource(sourcePath).getInputStream();
return this.saveFile(inputStream, "", fileName, append);
}
private boolean directoryExists(String dirPath) throws IOException {
ftpClient.changeWorkingDirectory(dirPath);
int returnCode = ftpClient.getReplyCode();
return returnCode != 550;
}
public boolean isConnected() {
boolean connected = false;
if (ftpClient != null) {
try {
connected = ftpClient.sendNoOp();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
log.debug("Checking for connection to FTP server. Is connected: " + connected);
return connected;
}
}
FTPFileWriter
接口:
import java.io.IOException;
import java.io.InputStream;
public interface FTPFileWriter {
/**
* Connects to a server and tries to log in the user.
*
* @return boolean True if successful, False otherwise.
*/
boolean open();
/**
* Logouts the current user and disconnects from the server.
*/
void close();
/**
* Retrieve a file from the ftp server.
*
* @param remotePath Remote path for the file to retrieve.
* @return boolean True if successful, False otherwise.
*/
InputStream loadFile(String remotePath);
boolean delete(String remotePath) throws IOException;
/**
* Store a file on the ftp server.
*
* @param inputStream Stream the new file is read from.
* @param dir
* @param destPath Remote path the file should be placed at.
* @param append Append to an existing file or write as a new file.
* @return boolean True if successful, False otherwise.
*/
String saveFile(InputStream inputStream, String dir, String destPath, boolean append) throws Exception;
/**
* Store a file on the ftp server.
*
* @param sourcePath Local path the file is read from.
* @param destPath Remote path the file should be placed at.
* @param append Append to an existing file or write as a new file.
* @return boolean True if successful, False otherwise.
*/
String saveFile(String sourcePath, String destPath, boolean append) throws Exception;
/**
* Does a NOOP to see if the connection is valid.
*
* @return boolean True if connected, False otherwise.
*/
boolean isConnected();
}
FTPProperties
是一个 class,它提供您的 ftp 设置:
public class FTPProperties {
private String server;
private String username;
private String password;
@Min(0)
@Max(65535)
private int port;
private int keepAliveTimout;
private boolean autoStart;
private String protocolType;
private String remoteDir;
@PostConstruct
public void init() {
if (port == 0) {
port = 21;
}
}
}
您可以实现自己的异常 classes 而不是 StorageException
和 StorageFileNotFoundException
或者抛出传统异常
如果你遇到 553 Could not create file
错误,它与 ftp 用户缺乏写入磁盘的权限有关,你可以通过 运行 在 [=35] 上执行命令来解决它=] ftp 主持人:
chown -R ftpusername /var/ftpfiles
将 /var/ftpfiles 替换为 ftp 存储文件夹的路径。
当我尝试在 ftp 服务器上上传文件时,我的 FtpClient
class 出现错误。我收到此消息:
220 (vsFTPd 3.0.3)
USER newftpuser
331 Please specify the password.
PASS ftp
230 Login successful.
TYPE I
200 Switching to Binary mode.
PORT 192,168,1,7,235,73
200 PORT command successful. Consider using PASV.
STOR /upload/logo.png
425 Failed to establish connection.
FtpClient.java
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
public class FtpClient {
private String server;
private int port;
private String user;
private String password;
private FTPClient ftp;
public void open() throws IOException {
ftp = new FTPClient();
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
ftp.enterLocalPassiveMode();
ftp.connect(server, port);
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
throw new IOException("Exception in connecting to FTP Server");
}
ftp.login(user, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
}
public void close() throws IOException {
ftp.disconnect();
}
public void putFileToPath(InputStream inputStream, String path) throws IOException {
ftp.storeFile(path, inputStream);
}
}
测试
@Test
public void dropFileOnFtpServer() throws IOException, URISyntaxException {
ftpClient = new FtpClient(...);
ftpClient.open();
InputStream inputStream = this.getClass().getResourceAsStream("/images/logo.png");
ftpClient.putFileToPath(inputStream, "/upload/logo.png");
assertTrue(ftpClient.listFiles("/upload").contains("logo.png"));
ftpClient.close();
}
已解决
问题的原因是被动模式。 appache.commons.net 的 FTPClient 在下载或上传文件之前需要手动启用被动模式,因此程序无法正常运行。
解决方案
public void putFileToPath(InputStream inputStream, String path) throws IOException {
ftp.enterLocalPassiveMode();
/* I enable this mode before connecting ftp, so client doesnt work*/
ftp.storeFile(path, inputStream);
}
请检查 Android FTP error - 425 Can't open data connection and Error: 425 Can't open data connection 并根据这些指南编辑您的配置。
我正在使用这个 class 进行 ftp 处理,您可以实现自己的异常处理和配置管理。
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPSClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
@Component
@Slf4j
public class FTPFileWriterImpl implements FTPFileWriter {
private final FTPProperties ftpProperties;
protected FTPClient ftpClient;
@Autowired
public FTPFileWriterImpl(@Autowired FTPProperties ftpProperties) {
this.ftpProperties = ftpProperties;
}
//@PostConstruct
public void init() {
if (this.ftpProperties.isAutoStart()) {
log.debug("Autostarting connection to FTP server.");
this.open();
}
}
public boolean open() {
close();
log.debug("Connecting and logging in to FTP server.");
if (ftpProperties.getProtocolType().equals("SSL"))
ftpClient = new FTPSClient();
else
ftpClient = new FTPClient();
ftpClient.enterLocalPassiveMode();
boolean loggedIn = false;
try {
ftpClient.connect(ftpProperties.getServer(), ftpProperties.getPort());
loggedIn = ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword());
if (loggedIn) {
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
if (ftpProperties.getKeepAliveTimout() > 0)
ftpClient.setControlKeepAliveTimeout(ftpProperties.getKeepAliveTimout());
} else {
log.error("Failed login to FTP server");
ftpClient.logout();
ftpClient.disconnect();
}
} catch (Exception e) {
log.error(e.getMessage());
}
return loggedIn;
}
public void close() {
if (ftpClient != null) {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
public InputStream loadFile(String fileName) {
try {
log.debug("Trying to retrieve a file from remote path " + fileName);
this.open();
return ftpClient.retrieveFileStream(fileName);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new StorageFileNotFoundException("File not found!");
} finally {
this.close();
}
}
public boolean delete(String fileName) throws IOException {
this.open();
boolean result = ftpClient.deleteFile(fileName);
this.close();
return result;
}
public String saveFile(InputStream inputStream, String dir, String fileName, boolean append) throws Exception {
log.debug("Trying to store a file to destination path " + fileName);
boolean result;
this.open();
try {
String saveDir = this.ftpProperties.getRemoteDir() + "/" + dir;
if (!directoryExists(saveDir)) {
boolean makeDirResult = this.ftpClient.makeDirectory(saveDir);
if(!makeDirResult) {
log.error("Storage directory {} does not exist on ftp server, failed to create it!", saveDir);
throw new StorageException("Storage directory {} does not exist on ftp server, failed to create it!");
}
}
String remote = saveDir + "/" + fileName;
if (append)
result = ftpClient.appendFile(remote, inputStream);
else
result = ftpClient.storeFile(remote, inputStream);
if (!result) {
log.error("Cannot save file on server, Server response is: {}", ftpClient.getReplyCode());
throw new StorageException(String.format("Cannot save file on server: %s", ftpClient.getReplyCode()));
}
return remote;
}
finally {
this.close();
}
}
public String saveFile(String sourcePath, String fileName, boolean append) throws Exception {
InputStream inputStream;
inputStream = new ClassPathResource(sourcePath).getInputStream();
return this.saveFile(inputStream, "", fileName, append);
}
private boolean directoryExists(String dirPath) throws IOException {
ftpClient.changeWorkingDirectory(dirPath);
int returnCode = ftpClient.getReplyCode();
return returnCode != 550;
}
public boolean isConnected() {
boolean connected = false;
if (ftpClient != null) {
try {
connected = ftpClient.sendNoOp();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
log.debug("Checking for connection to FTP server. Is connected: " + connected);
return connected;
}
}
FTPFileWriter
接口:
import java.io.IOException;
import java.io.InputStream;
public interface FTPFileWriter {
/**
* Connects to a server and tries to log in the user.
*
* @return boolean True if successful, False otherwise.
*/
boolean open();
/**
* Logouts the current user and disconnects from the server.
*/
void close();
/**
* Retrieve a file from the ftp server.
*
* @param remotePath Remote path for the file to retrieve.
* @return boolean True if successful, False otherwise.
*/
InputStream loadFile(String remotePath);
boolean delete(String remotePath) throws IOException;
/**
* Store a file on the ftp server.
*
* @param inputStream Stream the new file is read from.
* @param dir
* @param destPath Remote path the file should be placed at.
* @param append Append to an existing file or write as a new file.
* @return boolean True if successful, False otherwise.
*/
String saveFile(InputStream inputStream, String dir, String destPath, boolean append) throws Exception;
/**
* Store a file on the ftp server.
*
* @param sourcePath Local path the file is read from.
* @param destPath Remote path the file should be placed at.
* @param append Append to an existing file or write as a new file.
* @return boolean True if successful, False otherwise.
*/
String saveFile(String sourcePath, String destPath, boolean append) throws Exception;
/**
* Does a NOOP to see if the connection is valid.
*
* @return boolean True if connected, False otherwise.
*/
boolean isConnected();
}
FTPProperties
是一个 class,它提供您的 ftp 设置:
public class FTPProperties {
private String server;
private String username;
private String password;
@Min(0)
@Max(65535)
private int port;
private int keepAliveTimout;
private boolean autoStart;
private String protocolType;
private String remoteDir;
@PostConstruct
public void init() {
if (port == 0) {
port = 21;
}
}
}
您可以实现自己的异常 classes 而不是 StorageException
和 StorageFileNotFoundException
或者抛出传统异常
如果你遇到 553 Could not create file
错误,它与 ftp 用户缺乏写入磁盘的权限有关,你可以通过 运行 在 [=35] 上执行命令来解决它=] ftp 主持人:
chown -R ftpusername /var/ftpfiles
将 /var/ftpfiles 替换为 ftp 存储文件夹的路径。