Java &引用;期望/遵循URI中的主机名“;当密码包含@
我正在尝试将本地系统文件复制到服务器Java &引用;期望/遵循URI中的主机名“;当密码包含@,java,url,uri,sftp,apache-commons-vfs,Java,Url,Uri,Sftp,Apache Commons Vfs,我正在尝试将本地系统文件复制到服务器 package classes; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileSystemOptions; import org.ap
package classes;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemOptions;
import org.apache.commons.vfs.Selectors;
import org.apache.commons.vfs.impl.StandardFileSystemManager;
import org.apache.commons.vfs.provider.sftp.SftpFileSystemConfigBuilder;
public class SendMyFiles {
public static void main(String[] args) {
SendMyFiles sendMyFiles = new SendMyFiles();
String fileToFTP = "zcol_30092013.xls";
sendMyFiles.startFTP(fileToFTP);
}
public boolean startFTP(String fileToFTP){
Properties prop = new Properties();
InputStream in = getClass().getResourceAsStream("/config.properties");
StandardFileSystemManager manager = new StandardFileSystemManager();
try {
prop.load(in);
String serverAddress = prop.getProperty("serverAddress").trim();
String userId = prop.getProperty("userId").trim();
String password = prop.getProperty("password").trim();
String remoteDirectory = prop.getProperty("remoteDirectory").trim();
String localDirectory = prop.getProperty("localDirectory").trim();
System.out.println("Cheking values "+serverAddress+" "+userId+" "+password+" "+remoteDirectory+" "+localDirectory);
//check if the file exists
String filepath = localDirectory;
System.out.println("filepath "+filepath);
File file = new File(filepath);
System.out.println(file+" "+file.exists());
if (!file.exists())
throw new RuntimeException("Error. Local file not found");
//Initializes the file manager
manager.init();
//Setup our SFTP configuration
FileSystemOptions opts = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
opts, "no");
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
//Create the SFTP URI using the host name, userid, password, remote path and file name
String sftpUri= "sftp://" + userId + ":" + password + "@" + serverAddress + "/"
+ remoteDirectory+ fileToFTP;
// Create local file object
System.out.println("sftp uri "+sftpUri);
System.out.println(file.getAbsolutePath());
FileObject localFile = manager.resolveFile(file.getAbsolutePath());
// Create remote file object
FileObject remoteFile = manager.resolveFile(sftpUri, opts);
// Copy local file to sftp server
remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
System.out.println("File upload successful");
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
finally {
manager.close();
}
return true;
}
}
执行代码时出现以下异常:
org.apache.commons.vfs.FileSystemException:绝对URI无效”sftp://vmsorbit:***@172.16.16.148/universe/files/zcol_30092013.xls”。
位于org.apache.commons.vfs.provider.AbstractOriginatingFileProvider.findFile(AbstractOriginatingFileProvider.java:62)
位于org.apache.commons.vfs.impl.DefaultFileSystemManager.resolveFile(DefaultFileSystemManager.java:692)
位于org.apache.commons.vfs.impl.DefaultFileSystemManager.resolveFile(DefaultFileSystemManager.java:620)
位于classes.SendMyFiles.startFTP(SendMyFiles.java:67)
位于classes.SendMyFiles.main(SendMyFiles.java:23)
原因:org.apache.commons.vfs.FileSystemException:应在URI中的主机名后面sftp://vmsorbit:***@172.16.16.148/universe/files/zcol_30092013.xls”。
位于org.apache.commons.vfs.provider.HostFileNameParser.extractopath(HostFileNameParser.java:155)
位于org.apache.commons.vfs.provider.URLFileNameParser.parseUri(URLFileNameParser.java:49)
位于org.apache.commons.vfs.provider.AbstractFileProvider.parseUri(AbstractFileProvider.java:188)
位于org.apache.commons.vfs.provider.AbstractOriginatingFileProvider.findFile(AbstractOriginatingFileProvider.java:58)
... 4更多
获取第行中的错误
FileObject localFile = manager.resolveFile(file.getAbsolutePath());
密码包含特殊字符
@
如果密码包含@
,URL解析器将其视为用户信息/主机名分隔符。然后,它扫描主机名,在下一个@
上停止,这将分隔实际主机名。接下来,它检查主机名后面的第一个字符是否为/
,而不是原来的@
。这个逻辑对我来说没有多大意义,但解释了令人困惑的错误消息
应在URI中的主机名后面
但是在任何情况下,即使逻辑更好,您的密码或用户名中也不能有文字@
。您必须将其URL编码为%40
如果您的用户名/密码是可变的,则最好使用以下代码对其进行常规编码:
请注意,文档中的注释是错误的。它说该方法“从字符串中删除%nn个编码。”,但实际上却添加了它们。正如@martin prikryl的回答所述,某些字符不能以原始形式出现在用户名和密码字段中,否则它们将使URI无效 这里的根本原因是您正在使用简单的字符串连接来构造URI:
String sftpUri= "sftp://" + userId + ":" + password + "@" + serverAddress + "/"
+ remoteDirectory+ fileToFTP;
Java具有可用于从单个字段构造URI和URL的类。他们将正确处理每个字段的编码。您应该使用其中之一,而不是滚动您自己的逻辑:
import java.net.URI;
import java.net.URISyntaxException;
public class URITest {
public static void main(String[] args) throws URISyntaxException {
String user = "user";
String passwd = "p@ss/ord";
String host = "example.com";
String path = "/some/path";
String userInfo = user + ":" + passwd;
URI uri = new URI("sftp", userInfo, host, -1,
path, null, null);
System.out.println(uri.toString());
}
}
这张照片是:
sftp://user:p%40ss%2Ford@example.com/some/path
您的密码是否包含任何符号?是,它包含特殊字符@
sftp://user:p%40ss%2Ford@example.com/some/path