使用 HttpWebRequest 发布表单数据

Posted

技术标签:

【中文标题】使用 HttpWebRequest 发布表单数据【英文标题】:Post form data using HttpWebRequest 【发布时间】:2013-01-20 02:33:28 【问题描述】:

我想将一些表单数据发布到不在我自己的 Web 应用程序中的指定 URL。它具有相同的域,例如“domain.client.nl”。 Web 应用程序有一个 url “web.domain.client.nl”,我要发布到的 url 是“idp.domain.client.nl”。 但是我的代码什么也没做......有人知道我做错了什么吗?

沃特

StringBuilder postData = new StringBuilder();
postData.Append(HttpUtility.UrlEncode(String.Format("username=0&", uname)));
postData.Append(HttpUtility.UrlEncode(String.Format("password=0&", pword)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_success=0&", urlSuccess)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_failed=0", urlFailed)));

ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = ascii.GetBytes(postData.ToString());

// set up request object
HttpWebRequest request;
try

    request = (HttpWebRequest)HttpWebRequest.Create(WebSiteConstants.UrlIdp);

catch (UriFormatException)

    request = null;

if (request == null)
    throw new ApplicationException("Invalid URL: " + WebSiteConstants.UrlIdp);

request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

// add post data to request
Stream postStream = request.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Flush();
postStream.Close();

【问题讨论】:

可能重复:***.com/questions/5401501/… 不完全重复,因为另一个特别想使用WebClient 【参考方案1】:

您对表单的编码不正确。您应该只对值进行编码:

StringBuilder postData = new StringBuilder();
postData.Append("username=" + HttpUtility.UrlEncode(uname) + "&");
postData.Append("password=" + HttpUtility.UrlEncode(pword) + "&");
postData.Append("url_success=" + HttpUtility.UrlEncode(urlSuccess) + "&");
postData.Append("url_failed=" + HttpUtility.UrlEncode(urlFailed));

编辑

我错了。根据RFC1866 section 8.2.1,名称和值都应该被编码。

但是对于给定的示例,名称没有任何需要编码的字符,因此在这种情况下,我的代码示例是正确的;)

问题中的代码仍然不正确,因为它会对等号进行编码,这就是 Web 服务器无法对其进行解码的原因。

更合适的方法是:

StringBuilder postData = new StringBuilder();
postData.AppendUrlEncoded("username", uname);
postData.AppendUrlEncoded("password", pword);
postData.AppendUrlEncoded("url_success", urlSuccess);
postData.AppendUrlEncoded("url_failed", urlFailed);

//in an extension class
public static void AppendUrlEncoded(this StringBuilder sb, string name, string value)

    if (sb.Length != 0)
        sb.Append("&");
    sb.Append(HttpUtility.UrlEncode(name));
    sb.Append("=");
    sb.Append(HttpUtility.UrlEncode(value));

【讨论】:

谢谢,但现在我收到以下错误:远程服务器返回错误:(412) 前提条件失败。 我用谷歌搜索了很多 :) 但我修好了,我做的很肮脏。我没有 HttpWebRequest,但我在 String 中构建了一个 html 表单并将其写入浏览器(在 onload 中我会提交)。 @wsplinter:如果您记录了前置条件失败的解决方案,它将对其他人有所帮助。 @jgauffin :如何发布单选按钮值?假设我有 3 个单选按钮属于同一组。 显然,这对我来说并没有达到预期的效果,因为 UrlEncode 将 @ 之类的符号更改为 API 调用中不接受的代码;将其更改为使用 NameValueCollection,如@user3389691 的答案所示,效果很好。【参考方案2】:

字段名称和值都应该是 url 编码的。 post数据和查询字符串的格式是一样的

.net 的做法是这样的

NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("field1","value1");
outgoingQueryString.Add("field2", "value2");
string postdata = outgoingQueryString.ToString();

这将负责对字段和值名称进行编码

【讨论】:

string postdata = outgoingQueryString.ToString(); 会给你一个值为"System.Collections.Specialized.NameValueCollection"的字符串。 实际上@sfuqua 如果你反编译 HttpUtility 的源代码(特别是 System.Web 中的那个),你会看到它返回一个专门的 NameValueCollection 类型: return (NameValueCollection) new HttpValueCollection(query, false,真,编码);它将集合正确地转换为查询字符串。但是,如果您使用来自 RestSharp 的那个,它不会... 很有趣,因为我在ToString() 上看到了这个确切的问题,尽管我现在不记得它是否是在使用 RestSharp 时发生的。确定的可能性。谢谢指正。 目前还不清楚outgoingQueryString 是如何按照示例代码所暗示的那样工作的。这两个问题回答了 - (1) HttpValueCollection and NameValueCollection 和 (2) Any .NET class that makes a query string given key value pairs or the like。【参考方案3】:

试试这个:

var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");

var postData = "thing1=hello";
    postData += "&thing2=world";
var data = Encoding.ASCII.GetBytes(postData);

request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;

using (var stream = request.GetRequestStream())

    stream.Write(data, 0, data.Length);


var response = (HttpWebResponse)request.GetResponse();

var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

【讨论】:

我宁愿写:request.Method = WebRequestMethods.Http.Post; 在使用响应前检查 request.HaveResponse @MarcoFantasia 如果您检查request.HaveResponse,您实际上必须首先得到响应。 HttpWebResponse response = (HttpWebResponse) request.GetResponse(); if (request.HaveResponse) ... 【参考方案4】:

使用此代码:

internal void SomeFunction() 
    Dictionary<string, string> formField = new Dictionary<string, string>();
    
    formField.Add("Name", "Henry");
    formField.Add("Age", "21");
    
    string body = GetBodyStringFromDictionary(formField);
    // output : Name=Henry&Age=21


internal string GetBodyStringFromDictionary(Dictionary<string, string> formField)

    string body = string.Empty;
    foreach (var pair in formField)
    
        body += $"pair.Key=pair.Value&";   
    

    // delete last "&"
    body = body.Substring(0, body.Length - 1);

    return body;

【讨论】:

以上是关于使用 HttpWebRequest 发布表单数据的主要内容,如果未能解决你的问题,请参考以下文章

上传图像多部分表单 HTTPWebRequest - 将图像数据转换为字符串?

在 HttpWebRequest 文件发布时赢得表单应用程序冻结

阻止 HttpWebRequest 检查我的有效负载

利用HttpWebRequest模拟表单提交

C# HttpWebRequest 表单上传

HttpWebRequest 表单提交