使用 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 - 将图像数据转换为字符串?