Публикация данных формы с помощью HttpWebRequest

91

Я хочу отправить некоторые данные формы по указанному URL-адресу, который не находится в моем собственном веб-приложении. У него такой же домен, например, «domain.client.nl». У веб-приложения есть 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();
wsplinter
источник
Возможный дубликат: stackoverflow.com/questions/5401501/…
Дариуш
6
Не совсем дубликат, который другой специально хочет использовать WebClient.

Ответы:

72

И имя поля, и значение должны быть закодированы по URL-адресу. формат данных публикации и строки запроса одинаковы

Способ .net сделать что-то вроде этого

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

Это позаботится о кодировании полей и имен значений

пользователь3389691
источник
10
string postdata = outgoingQueryString.ToString();даст вам строку со значением "System.Collections.Specialized.NameValueCollection".
sfuqua
1
На самом деле @sfuqua, если вы декомпилируете источник для HttpUtility (в частности, тот, который находится в System.Web), вы увидите, что он возвращает специализированный тип NameValueCollection: return (NameValueCollection) new HttpValueCollection (query, false, true, encoding); который правильно преобразует коллекцию в строку запроса. Однако, если вы используете один из RestSharp, он не ...
Сенатор
Интересно, что я видел именно эту проблему ToString(), хотя сейчас не могу вспомнить, было ли это при использовании RestSharp. Определенная возможность. Спасибо за исправление.
sfuqua
Было не сразу понятно, как outgoingQueryStringработает пример кода. Эти два вопроса ответить на этот вопрос - (1) HttpValueCollection и NameValueCollection и (2) Любой .NET класс , который делает строку запроса данного ключа значение пары или тому подобное .
Кенни Эвитт
57

Попробуй это:

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();
Париса Шамсайе
источник
6
Я бы предпочел написать: request.Method = WebRequestMethods.Http.Post;
Totalys
проверить запрос.HaveResponse before use response
Marco Fantasia
@MarcoFantasia Если вы проверите, request.HaveResponseвы должны сначала получить ответ. HttpWebResponse response = (HttpWebResponse) request.GetResponse(); if (request.HaveResponse) { ... }
Yes Barry
41

Вы неправильно кодируете форму. Вы должны только кодировать значения:

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, раздел 8.2.1, имена и значения должны быть закодированы.

Но для данного примера в именах нет символов, которые необходимо кодировать, поэтому в этом случае мой пример кода верен;)

Код в вопросе все еще неверен, поскольку он кодирует знак равенства, который является причиной того, почему веб-сервер не может его декодировать.

Более правильный способ был бы:

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) Precondition Failed.
wsplinter 05
Много гуглил :) Но починил, по грязи делаю. Я не использую HttpWebRequest, но я создаю html-форму внутри String и отправляю ее в браузер (в onload я сделаю отправку).
wsplinter 05
3
@wsplinter: Это поможет другим, если вы задокументируете решение для предварительного условия.
jgauffin 02
@jgauffin: Как разместить значения переключателей? Предположим, у меня есть 3 переключателя, принадлежащих к одной группе.
Асад Рефаи,
1
По-видимому, у меня это не сработало так, как ожидалось, поскольку UrlEncode заменяет символы вроде @ на код, который не принимался при вызове API; изменение его на использование NameValueCollection как showin в ответе @ user3389691 работает отлично.
дхрувпател 09