Публикация данных формы с помощью 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();

Возможный дубликат: 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();

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


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.