当密码包含@符号时,在URI中期望/跟随主机名。

9

我正在尝试将本地系统文件复制到服务器

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: Invalid absolute URI "sftp://vmsorbit:***@172.16.16.148/universe/files/zcol_30092013.xls".
    at org.apache.commons.vfs.provider.AbstractOriginatingFileProvider.findFile(AbstractOriginatingFileProvider.java:62)
    at org.apache.commons.vfs.impl.DefaultFileSystemManager.resolveFile(DefaultFileSystemManager.java:692)
    at org.apache.commons.vfs.impl.DefaultFileSystemManager.resolveFile(DefaultFileSystemManager.java:620)
    at classes.SendMyFiles.startFTP(SendMyFiles.java:67)
    at classes.SendMyFiles.main(SendMyFiles.java:23)
Caused by: org.apache.commons.vfs.FileSystemException: Expecting / to follow the hostname in URI "sftp://vmsorbit:***@172.16.16.148/universe/files/zcol_30092013.xls".
    at org.apache.commons.vfs.provider.HostFileNameParser.extractToPath(HostFileNameParser.java:155)
    at org.apache.commons.vfs.provider.URLFileNameParser.parseUri(URLFileNameParser.java:49)
    at org.apache.commons.vfs.provider.AbstractFileProvider.parseUri(AbstractFileProvider.java:188)
    at org.apache.commons.vfs.provider.AbstractOriginatingFileProvider.findFile(AbstractOriginatingFileProvider.java:58)
    ... 4 more

在这一行出现错误

FileObject localFile = manager.resolveFile(file.getAbsolutePath());

该密码包含特殊字符@


2
你的密码包含任何符号吗? - Martin Prikryl
2
是的,它包含特殊字符 @。 - Karan Patel
3个回答

7
如果您的密码包含@符号,URL解析器会将其视为userinfo/hostname分隔符。然后它会扫描主机名,在下一个@处停止,该符号分隔实际主机名。接下来,它会检查主机名后的第一个字符是否为/,但实际上不是,因为它是@。这个逻辑对我来说没有太多意义,但可以解释令人困惑的错误消息:

期望URI中主机名后跟着 /

但无论如何,即使逻辑更好,您也不能在您的密码或用户名中使用文字@。您必须将其编码为%40
如果您的用户名/密码是可变的,最好使用UriParser.encode进行通用编码。
public static String encode(String decodedStr)

请注意文档中的注释是错误的。它说这个方法“从字符串中删除%nn编码”,但实际上它会将它们添加进去。

7
正如@martin-prikryl的回答所述,某些字符不能以原始形式出现在用户名和密码字段中,否则它们将使URI无效。
根本原因在于您正在使用简单的字符串连接来构建URI:
String sftpUri= "sftp://" + userId + ":" + password + "@" + serverAddress + "/"
+ remoteDirectory+ fileToFTP;

Java提供了URIURL类,用于从单独的字段构建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

0
在尝试连接文件连接器时,我遇到了这个错误,错误发生在WSO2 EI 6.6.0版本。 首先,我尝试了下面这个方法,但是出现了错误。
{
    "source": "ftp://username:Pass@word@host/home/In/Test.pdf"
}

然后我将@作为%40传递给密码,然后它就正常工作了。问题是由于@也用于分隔主机名,所以如果我们在密码中传递@,它会被视为主机分隔符。
请使用以下方式:
{ 
    "source": "ftp://username:Pass%40word@host/home/In/Test.pdf"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接