使用 HttpWebRequest 通过 PUT 上传文件时出错

Posted

技术标签:

【中文标题】使用 HttpWebRequest 通过 PUT 上传文件时出错【英文标题】:Error using HttpWebRequest to upload files with PUT 【发布时间】:2010-10-18 13:51:08 【问题描述】:

我们有一个 .NET 2.0 WinForms 应用程序,它需要通过 WebDav 将文件上传到 IIS6 服务器。我们不时收到来自远程办公室的投诉,称他们收到以下错误消息之一

基础连接已关闭: 发送时发生意外错误。 基础连接已关闭: 发生意外错误 接收。

这似乎只发生在大文件(约 20Mb 以上)中。我已经使用家用计算机上的 40Mb 文件对其进行了测试,并尝试将“睡眠”置于循环中以模拟慢速连接,因此我怀疑它最终归结为网络问题......但是

    远程办公室的 IT 无济于事 我想排除我的代码有问题的可能性。

所以 - 任何人都可以发现任何错误或建议任何可能“防弹”代码针对此问题的解决方法。谢谢你的帮助。删减版代码如下:

    public bool UploadFile(string localFile, string uploadUrl)
    
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uploadUrl);

        try
        
            req.Method = "PUT";
            req.AllowWriteStreamBuffering = true;
            req.UseDefaultCredentials = Program.WebService.UseDefaultCredentials;
            req.Credentials = Program.WebService.Credentials;
            req.SendChunked = false;
            req.KeepAlive = true;
            Stream reqStream = req.GetRequestStream();
            FileStream rdr = new FileStream(localFile, FileMode.Open, FileAccess.Read);
            byte[] inData = new byte[4096];
            int bytesRead = rdr.Read(inData, 0, inData.Length);

            while (bytesRead > 0)
            
                reqStream.Write(inData, 0, bytesRead);
                bytesRead = rdr.Read(inData, 0, inData.Length);
            

            reqStream.Close();
            rdr.Close();

            System.Net.HttpWebResponse response = (HttpWebResponse)req.GetResponse();
            if (response.StatusCode != HttpStatusCode.OK && response.StatusCode!=HttpStatusCode.Created)
            
                MessageBox.Show("Couldn't upload file");
                return false;
            
        
        catch (Exception ex)
        
            MessageBox.Show(ex.ToString());
            return false;
        
        return true;
    

【问题讨论】:

什么webdav客户端和服务器? 【参考方案1】:

尝试将KeepAlive 设置为false:

req.KeepAlive = false;

这将允许关闭并再次打开连接。它不允许使用persistent connection。我在网上找到了很多建议这样做的参考资料,以解决与您的错误类似的错误。这是一个相关的link。

无论如何,使用 HTTP PUT(或 HTTP POST)上传大文件并不是一个好主意。最好使用 FTP 或下载/上传管理器。这些将自动为您处理重试、连接问题、超时。上传速度也会更快,您也可以恢复停止的上传。如果您决定继续使用 HTTP,您至少应该尝试添加重试机制。如果上传时间过长,则很有可能由于代理、服务器超时、防火墙或任何不使用您的代码的原因而失败。

【讨论】:

【参考方案2】:

要消除代码中出现错误的风险,请尝试使用WebClient

using (WebClient client = new WebClient())

    client.UseDefaultCredentials = Program.WebService.UseDefaultCredentials;
    client.Credentials = Program.WebService.Credentials;
    client.UploadFile(uploadUrl, "PUT", localFile);

【讨论】:

URL 必须包含目标文件名吗? 我希望如此,但这取决于服务器。 @MarcGravell,在你的例子中什么是有效的 uploadUrl ? uploadUrl 指向任何目标方法,或者它指向目标文件夹,它本身将被放置。 @KumarHarsh 这完全由网络应用决定; PUT 请求只是一个带有不同动词的常规 HTTP 请求(而不是 GETHEADPOST 等)。网络应用做什么:完全取决于应用。【参考方案3】:

也许尝试使用 POST,但真正的罪魁祸首可能是内容类型。

尝试设置

req.ContentType = "application/octet-stream";
req.ContentLength = inData.Length;

或在此处查看已接受答案中的代码:Upload files with HTTPWebrequest (multipart/form-data)

我的示例和我提供的链接都涉及修改 ContentType - 我的示例更简单但可能不起作用,因为大多数接收文件的应用程序都需要多部分

【讨论】:

这不会导致间歇性问题。【参考方案4】:

请检查在 IIS 管理器的 [Web Site] 选项卡中 [Enable Http Keep-Alives] 是否设置为 [on]。

【讨论】:

【参考方案5】:

上传的大小可能会受到限制。

这里有一个讨论: http://www.codeproject.com/KB/aspnet/uploadlargefilesaspnet.aspx

【讨论】:

不是这样,WebDAV 传输不打 ASP.NET,我可以自己从不同的远程网络上传相同的文件。【参考方案6】:

首先检查一些基本配置。以下任一的默认值可能会导致文件上传出现问题 - 包括连接终止。我相信 IIS 6 永远不会允许文件上传 > 2GB(即使它可以完成,无论配置如何)。 Msdn describes these nicely.

<httpRuntime executionTimeout = "30"  maxRequestLength="200"/>

编辑:当然,这是 ASP.NET 配置,它假定您正在运行自己的 webdav 服务器或 ASP.NET 中的3rd party server。如果它是不同的 webdav 服务器,您将需要寻找等效的。

【讨论】:

以上是关于使用 HttpWebRequest 通过 PUT 上传文件时出错的主要内容,如果未能解决你的问题,请参考以下文章

HTTPWebRequest.GetResponse() 通过透明代理验证请求失败

使用 HttpWebRequest 通过 SSL 发送请求时出现错误 502(错误网关)

是否可以通过 httpwebrequest 使用 WCF 服务(托管为 Windows 服务托管)?

如何通过httpwebrequest访问使用证书登录的网站

为啥通过 .Net 代理的 HttpWebrequest 失败?

通过HttpWebRequest调用webService