20

有没有办法在 HTTP 代理后面将文件上传到 FTP 服务器?

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

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

编辑:不幸的是,我没有任何 FTP 代理可以连接。

4

13 回答 13

9

在主动 FTP 模式下,服务器向客户端发起数据连接。如果客户端在 HTTP 代理后面,这显然是行不通的。在被动 FTP 模式下,发起初始连接和数据连接的是客户端。由于 HTTP 代理可以通过隧道传输任意传出 TCP 连接(使用 CONNECT 方法),因此应该可以通过 HTTP 代理以被动模式访问 FTP 服务器。

FtpWebRequest似乎支持被动模式。但是,我不明白为什么支持文件下载和目录列表,而同样使用相同数据连接的文件上传却不支持。

您是否确认FtpWebRequest配置为被动模式不能通过 HTTP 代理工作,通过该代理目录列表/文件下载工作正常?

于 2008-10-02T11:29:13.987 回答
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();
于 2009-05-28T07:43:00.087 回答
5

大多数 FTP 代理在连接上做他们的事情,所以如果你没有代理,你这样做:

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

使用 FTP 代理,您可以:

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

它只是从那里解决问题。我正在通过 squid 代理使用这个 RIGHT THIS SECOND(试图调试某些东西)。

...但是由于您没有 FTP 代理....

你有 SOCKS 代理吗?这可能有效,但我不知道.NET 是否可以做到。否则,老实说,我认为你被卡住了!与 HTTP 相比,FTP 是一种“奇怪”的协议,因为它有一个控制通道(端口 21)和一个数据通道(或多个,在一个随机端口上),所以通过代理是……有趣至少说!

于 2008-10-02T11:31:57.207 回答
4

从 .NET 框架 4.8 开始,FtpWebRequest仍然无法通过 HTTP 代理上传文件

如果指定的代理是 HTTP 代理,则仅支持 DownloadFile、ListDirectory 和 ListDirectoryDe​​tails 命令。

它可能永远不会像FtpWebRequest现在被弃用的那样。所以你需要使用第 3 方 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();
}

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

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

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

(我是WinSCP的作者)

于 2015-11-03T15:34:23.607 回答
3

一种解决方案是尝试 Mono 的 FtpWebRequest 实现。我查看了它的源代码,它似乎很容易修改,以便所有连接(控制和数据)都通过 HTTP 代理进行隧道传输。

您建立到 HTTP 代理的 TCP 连接,而不是实际的 FTP 服务器。然后你发送CONNECT myserver:21 HTTP/1.0后跟两个 CRLF (CRLF = \r\n)。如果代理需要身份验证,您需要使用 HTTP/1.1 并发送带有凭据的代理身份验证标头。然后你需要阅读响应的第一行。如果它以“ HTTP/1.0 200 ”或“ HTTP/1.1 200 ”开头,那么您(其余代码)可以继续使用该连接,就好像它直接连接到 FTP 服务器一样。

于 2008-10-02T13:40:26.777 回答
2

正如 Alexander 所说,HTTP 代理可以代理任意流量。您需要的是支持使用 HTTP 代理的 FTP 客户端。亚历山大也是正确的,这只能在被动模式下工作。

我的雇主销售这样一个 FTP 客户端,但它是一个企业级工具,仅作为一个非常大的系统的一部分提供。

我敢肯定,还有其他更适合您的需求。

于 2008-10-02T12:09:37.570 回答
2

如果有一种方法可以让您在没有C# 的情况下通过 FTP 上传文件,那么在 C# 中也应该可以。通过浏览器或 FTP 客户端上传是否有效?

我最喜欢的一个 FTP 库是.NET FTP 客户端库

于 2008-10-02T11:42:05.483 回答
2

通过 HTTP 代理将内容上传到 ftp:// URL 的标准方法是使用 HTTP PUT 请求。在处理 ftp:// URL 时,HTTP 代理充当 HTTP<->FTP 网关,向请求客户端发送 HTTP,向请求的 FTP 服务器发送 FTP。

至少 Squid HTTP 代理支持 PUT 到 ftp:// URL,不确定其他代理做什么。

更常见的方法是滥用 CONNECT 方法在代理上建立隧道。但这通常是不允许的,因为允许在代理上建立双向隧道的安全隐患。

于 2011-06-27T22:20:24.517 回答
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;

这为我解决了这个问题。

于 2013-02-01T13:49:34.133 回答
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;
    }
于 2013-12-03T14:25:13.557 回答
-1

我刚刚遇到了同样的问题。

我的主要目标是将文件上传到 ftp。而且我不在乎我的流量是否会通过代理。

所以我刚刚在 FTPWebRequest.Create(uri) 之后将 FTPWebRequest.Proxy 属性设置为 null。

它奏效了。是的,我知道这个解决方案不是最好的。还有更多,我不明白为什么它会起作用。但无论如何,目标已经完成。

于 2009-09-04T10:55:20.367 回答
-1

我不确定所有 HTTP 代理是否都以相同的方式工作,但我设法通过简单地创建一个 HTTP 请求来访问 URI ftp://user:pass@your.server.com/path上的资源来欺骗我们的代理。

遗憾的是,要创建 HttpWebRequest 的实例,您应该使用 WebRequest.Create。如果这样做,您将无法为 ftp:// 模式创建 HTTP 请求。

所以我使用了一些反射来调用一个非公共构造函数,它这样做:

var ctor = typeof(HttpWebRequest).GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, 
    null, 
    new Type[] { typeof(Uri), typeof(ServicePoint) }, 
    null);
var req = (WebRequest)ctor.Invoke(new object[] { new Uri("ftp://user:pass@host/test.txt"), null });
req.Proxy = new WebProxy("myproxy", 8080);
req.Method = WebRequestMethods.Http.Put;

using (var inStream = req.GetRequestStream())
{
    var buffer = Encoding.ASCII.GetBytes("test upload");
    inStream.Write(buffer, 0, buffer.Length);
}

using (req.GetResponse())
{
}

您还可以对其他任务使用其他方法,例如“DELETE”。

就我而言,它就像一个魅力。

于 2013-11-14T12:02:37.573 回答
-5

我并没有真正看到 http 代理和上传到 ftp 服务器之间的连接。如果您使用 http 代理类,那就是通过 http 代理访问 http 资源。ftp 是另一种协议,而 ftp 代理使用不同的协议。

于 2008-10-02T08:04:54.943 回答