使用HTTP代理上传FTP文件

20

当使用HTTP代理时,是否有方法将文件上传到FTP服务器?

似乎使用.Net Webclient在HTTP代理后面不支持上传文件。(http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.proxy.aspx)。

如果没有解决方案?如果没有,你知道我可以使用哪个好用的免费FTP库吗?

编辑:很遗憾,我没有FTP代理连接。

13个回答

9
在主动FTP模式下,服务器会向客户端发起数据连接。如果客户端在HTTP代理后面,这显然是行不通的。在被动FTP模式下,客户端会发起初始连接和数据连接。由于HTTP代理可以通过使用CONNECT方法隧道传输任意出站TCP连接,因此应该可以通过HTTP代理以被动模式访问FTP服务器。
看起来FtpWebRequest支持被动模式。但是,我不明白为什么支持文件下载和目录列表,而使用相同数据连接的文件上传却不支持。
您是否确认已配置为被动模式的FtpWebRequest无法通过HTTP代理工作,而通过该代理进行目录列表/文件下载却可以正常工作?

4
这个缺陷有记录:“如果指定的代理是HTTP代理,则仅支持DownloadFile、ListDirectory和ListDirectoryDetails命令。”- http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.proxy.aspx - Jonas Elfström

5

大多数FTP代理都在连接时进行操作,因此如果您没有代理,则可以执行以下操作:

  • 服务器:myftpserver.com
  • 用户:me
  • 密码:pwd

使用FTP代理,您需要执行以下操作:

  • 服务器:ftpproxy.mydomain.com
  • 用户:me@myftpserver.com
  • 密码:pwd

然后它会自动解决。我正在通过squid代理(尝试调试某些内容)使用这个方法。

但是,如果您没有FTP代理...

您有SOCKS代理吗?那可能行得通,但我不知道.NET是否支持。否则,说实话,我认为您卡住了!与HTTP相比,FTP是一种“奇怪”的协议,因为它具有控制通道(端口21)和数据通道(或更多,随机端口),因此通过代理进行传输...最好说它很有趣!


他没有FTP代理。 - VVS
抱歉,我错过了那一部分。正在编辑。 - Nic Wise

5

我们的Rebex FTP/SSL可以使用HTTP代理。但是这是需要付费的...

// initialize FTP client 
Ftp client = new Ftp();

// setup proxy details  
client.Proxy.ProxyType = FtpProxyType.HttpConnect;
client.Proxy.Host = proxyHostname;
client.Proxy.Port = proxyPort;

// add proxy username and password when needed 
client.Proxy.UserName = proxyUsername;
client.Proxy.Password = proxyPassword;

// connect, login 
client.Connect(hostname, port);
client.Login(username, password);

// do some work 
// ... 

// disconnect 
client.Disconnect();

我有使用Rebex FTP/FTPS库的多年经验,它解决了我所有的问题。我强烈推荐这个库,因为它为我节省了大量的时间和金钱。 - TcKs

4
自从.NET Framework 4.8开始,FtpWebRequest仍然不能通过HTTP代理上传文件。如果指定的代理是HTTP代理,则仅支持DownloadFile、ListDirectory和ListDirectoryDetails命令。而且它可能永远都不会支持,因为FtpWebRequest现已弃用。所以你需要使用第三方FTP库。
例如,使用WinSCP .NET组件时,你可以使用以下代码:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "example.com",
    UserName = "user",
    Password = "mypassword",
};

// Configure proxy
sessionOptions.AddRawSettings("ProxyMethod", "3");
sessionOptions.AddRawSettings("ProxyHost", "proxy");

using (Session session = new Session())
{
    // Connect
    session.Open(sessionOptions);

    // Upload file
    string localFilePath = @"C:\path\file.txt";
    string pathUpload = "/file.txt";
    session.PutFiles(localFilePath, pathUpload).Check();
}

有关 SessionOptions.AddRawSettings 的选项,请参见原始设置

更简单的方法是让WinSCP GUI为您生成C#FTP代码模板

请注意,WinSCP .NET程序集不是本机.NET库,而是一个在控制台应用程序上的薄.NET包装器。

(我是WinSCP的作者)


3
一种解决方案是尝试使用Mono的FtpWebRequest实现。我查看了它的源代码,似乎很容易修改,以便所有连接(控制和数据)都通过HTTP代理隧道传输。
您需要建立到HTTP代理的TCP连接,而不是实际的FTP服务器。然后,您发送CONNECT myserver:21 HTTP/1.0,然后是两个CRLFs(CRLF = \r\n)。如果代理需要身份验证,则需要使用HTTP/1.1,并在凭据中发送代理身份验证标头。然后,您需要读取响应的第一行。如果以"HTTP/1.0 200 "或"HTTP/1.1 200 "开头,则您(其余代码)可以继续使用该连接,就像直接连接到FTP服务器一样。

2
使用HTTP PUT请求是上传内容到ftp:// URL的标准方式,通过HTTP代理进行。当处理ftp:// URL时,HTTP代理充当HTTP<->FTP网关,向请求客户端发出HTTP请求并向请求的FTP服务器发出FTP请求。
至少Squid HTTP代理支持将PUT请求发送到ftp:// URL,不确定其他代理是否支持。
更常见的方法是滥用CONNECT方法,在代理上建立隧道。但是由于允许代理上的双向隧道会带来安全问题,因此通常不允许这样做。

2

如果你能通过FTP上传文件,而不需要使用C#,那么在C#中也应该可以实现。是否可以通过浏览器或FTP客户端上传?

我最喜欢的FTP库是.NET FTP Client library


它是否支持通过HTTP代理进行隧道传输?我查看了概述(http://sourceforge.net/docman/display_doc.php?docid=19518&group_id=92889),但没有找到任何关于代理的参考。 - Alexander
我猜,如果上述FTP客户端在被动模式下工作正常,那么你可以轻松修改其源代码以隧道TCP连接(这大约是Java中的20行代码)。 - Alexander
@Alexander:我必须承认,我只是用它来代理FTP,就像使用普通的FTP服务器一样。 - VVS
源代码中没有代理支持的迹象。 - Jonas Elfström

2
如亚历山大所说,HTTP代理可以代理任意流量。您需要的是支持使用HTTP代理的FTP客户端。亚历山大也正确指出,这只适用于被动模式。
我的雇主销售这样的FTP客户端,但它是一个企业级工具,只作为一个非常庞大的系统的一部分提供。
我相信有其他更适合您需求的FTP客户端可用。

2

你好,我遇到了同样的问题 - 解决方法是创建代理对象并派生默认凭据 - 只要你的应用程序使用网络帐户运行,这应该是可以的 -

FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));

System.Net.WebProxy proxy = System.Net.WebProxy.GetDefaultProxy();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;

// set the ftpWebRequest proxy
reqFTP.Proxy = proxy;

这对我解决了问题。

0

这些不自由的应用程序和组件真是讨厌!!! 这里是我的开源C#代码,可以通过HTTP代理上传文件到FTP。

        public bool UploadFile(string localFilePath, string remoteDirectory)
    {
        var fileName = Path.GetFileName(localFilePath);
        string content;
        using (var reader = new StreamReader(localFilePath))
            content = reader.ReadToEnd();

        var proxyAuthB64Str = Convert.ToBase64String(Encoding.ASCII.GetBytes(_proxyUserName + ":" + _proxyPassword));
        var sendStr = "PUT ftp://" + _ftpLogin + ":" + _ftpPassword
            + "@" + _ftpHost + remoteDirectory + fileName + " HTTP/1.1\n"
            + "Host: " + _ftpHost + "\n"
            + "User-Agent: Mozilla/4.0 (compatible; Eradicator; dotNetClient)\n" + "Proxy-Authorization: Basic " + proxyAuthB64Str + "\n"
            + "Content-Type: application/octet-stream\n"
            + "Content-Length: " + content.Length + "\n"
            + "Connection: close\n\n" + content;

        var sendBytes = Encoding.ASCII.GetBytes(sendStr);

        using (var proxySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            proxySocket.Connect(_proxyHost, _proxyPort);
            if (!proxySocket.Connected)
                throw new SocketException();
            proxySocket.Send(sendBytes);

            const int recvSize = 65536;
            var recvBytes = new byte[recvSize];
            proxySocket.Receive(recvBytes, recvSize, SocketFlags.Partial);

            var responseFirstLine = new string(Encoding.ASCII.GetChars(recvBytes)).Split("\n".ToCharArray()).Take(1).ElementAt(0);
            var httpResponseCode = Regex.Replace(responseFirstLine, @"HTTP/1\.\d (\d+) (\w+)", "$1");
            var httpResponseDescription = Regex.Replace(responseFirstLine, @"HTTP/1\.\d (\d+) (\w+)", "$2");
            return httpResponseCode.StartsWith("2");
        }
        return false;
    }

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