使用.NET向服务器发布文件的方法:HttpWebRequest或WebClient。

8

好的,这里是问题。正如问题所述,我正在尝试将文件POST到Web服务器,并且遇到了一些问题。

我已经尝试使用Curl.exe将相同的文件POST到同一个Web服务器,并没有遇到任何问题。我已经贴出了我在curl中使用的标志,以防它们可能指出为什么我在.NET类方面遇到麻烦的潜在原因。

curl.exe --user "myUser:myPass" --header "Content-Type: application/gzip"  
--data-binary "@filename.txt.gz" --cookie "data=service; data-ver=2; date=20100212;  
time=0900; location=1234" --output "out.txt" --dump-header "header.txt"  
http://mysite/receive

我试图使用像WebClient或HttpWebRequest这样的.NET类来完成同样的事情。以下是我尝试过的代码示例。使用WebClient时,我会收到505 HTTP版本不受支持的错误,而使用HttpWebRequest时,我会收到501未实现的错误。
在使用WebClient时:
public void sendFileClient(string path){
    string url = "http://mysite/receive";  
    WebClient wc = new WebClient();  
    string USERNAME = "myUser";  
    string PSSWD = "myPass";  

    NetworkCredential creds = new NetworkCredential(USERNAME, PSSWD);  
    wc.Credentials = creds;  
    wc.Headers.Set(HttpRequestHeader.ContentType, "application/gzip");  
    wc.Headers.Set("Cookie", "location=1234; date=20100226; time=1630; data=service; data-ver=2");  

    wc.UploadFile(url, "POST", path);
}

使用 HttpRequest 时:

public Stream sendFile(string path)
{
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://myserver/receive");  
    string USERNAME = "myUser";    
    string PSSWD = "myPass";  
    NetworkCredential creds = new NetworkCredential(USERNAME, PSSWD);  
    request.Credentials = creds;  
    request.Method = "POST";  
    request.ContentType = "application/gzip";    
    request.Headers.Set("Cookie", "location=1234; date=20100226; time=1630; data=service; data-ver=2");  
    FileInfo fInfo = new FileInfo(path);  
    long numBytes = fInfo.Length;  
    FileStream fStream = new FileStream(path, FileMode.Open, FileAccess.Read);  
    BinaryReader br = new BinaryReader(fStream);  
    byte[] data = br.ReadBytes((int)numBytes);  
    br.Close();  
    fStream.Close();  
    fStream.Dispose();  
    Stream wrStream = request.GetRequestStream();  
    BinaryWriter bw = new BinaryWriter(wrStream);  
    bw.Write(data);  
    bw.Close();  
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();  
    return response.GetResponseStream();  
}

1
使用调试HTTP代理来查看两个调用之间的差异。尝试使用Charles(http://www.charlesproxy.com/)或Fiddler(http://www.fiddler2.com/fiddler2/)。 - Samuel Neff
2个回答

10

首先,使用类似fiddler的工具检查请求和响应,以查看curl和System.Net.WebClient之间的区别。

此外,您可以尝试以下操作(尽管使用调试代理进行检查应该能够准确定位差异):

使用凭据缓存来设置基本身份验证凭据:

var cc= new CredentialCache();
cc.Add(new Uri(url),
                  "Basic", 
                  new NetworkCredential("USERNAME", "PASSWORD"));
wc.Credentials = cc;

设置用户代理标头:

string _UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
wc.Headers.Add(HttpRequestHeader.UserAgent, _UserAgent);

更改 WebRequest 的协议版本:

reqeust.KeepAlive = false;
request.ProtocolVersion=HttpVersion.Version10;

"更改 WebRequest 上的协议版本" 做到了! - Myishmael
类似问题:为请求添加用户代理标头,这个方法解决了我的问题。 - Jere.Jones

1

当501协议出现时,可能还有另外两个原因。

----------1---------

当发布日期包含一些中文字符或其他字符时,例如:

postDate = "type=user&username=计算机学院&password=123&Submit=+登录+"

为了发布正确的信息,您还可以添加以下两行;

Request.SendChunked = true;
Request.TransferEncoding = "GB2312";

这也导致了一个501错误。

在这种情况下,您可以删除第2行,并将postDate修改为以下内容。

postDate = "type=user&username=%BC%C6%CB%E3%BB%FA%D1%A7%D4%BA&password=123&Submit=+%C8%B7%C8%CF+"

也许这是修改postDate的解决方案,但我还没有测试过。

string str = Encoding.GetEncoding("gb2312").GetString(tmpBytes);

----------2---------

如果 Response.StatusCode == HttpStatusCode.Redirect,那么 Redirect 等于 302。 以下这行代码是必须的:

Request.AllowAutoRedirect = false;

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