โพสต์ข้อมูลแบบฟอร์มโดยใช้ HttpWebRequest


91

ฉันต้องการโพสต์ข้อมูลแบบฟอร์มบางส่วนไปยัง URL ที่ระบุซึ่งไม่ได้อยู่ในเว็บแอปพลิเคชันของฉันเอง มีโดเมนเดียวกันเช่น "domain.client.nl" เว็บแอปพลิเคชันมี url "web.domain.client.nl" ซึ่ง URL ที่ฉันต้องการโพสต์คือ "idp.domain.client.nl" แต่รหัสของฉันไม่ทำอะไรเลย ..... มีใครรู้บ้างว่าฉันทำผิด?

Wouter

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/…
Dariusz

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) ใหม่ HttpValueCollection (แบบสอบถามเท็จจริงการเข้ารหัส); ซึ่งแปลงคอลเลกชันเป็นสตริงแบบสอบถามได้อย่างถูกต้อง อย่างไรก็ตามหากคุณใช้อันนี้จาก RestSharp มันจะไม่ ...
วุฒิสมาชิก

น่าสนใจอย่างที่ฉันเคยเห็นปัญหาที่แน่นอนนี้ToString()แม้ว่าตอนนี้ฉันจำไม่ได้แล้วว่าเป็นขณะใช้ RestSharp หรือไม่ ความเป็นไปได้ที่แน่นอน ขอบคุณสำหรับการแก้ไข
sfuqua

ยังไม่ชัดเจนในทันทีว่าoutgoingQueryStringทำงานอย่างไรตามที่ระบุโดยนัยของโค้ดตัวอย่าง คำถามสองข้อนี้ตอบว่า - (1) HttpValueCollection และ NameValueCollectionและ (2) คลาส. NET ใด ๆ ที่สร้างสตริงการสืบค้นที่กำหนดคู่ค่าคีย์หรือสิ่งที่คล้ายกัน
Kenny Evitt

58

ลองสิ่งนี้:

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

check request.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) เงื่อนไขเบื้องต้นล้มเหลว
wsplinter

ฉันใช้ Google เยอะมาก :) แต่ฉันแก้ไขแล้วฉันกำลังทำสิ่งสกปรก ฉันไม่ได้เป็น HttpWebRequest แต่ฉันสร้างแบบฟอร์ม html ภายใน String และส่งไปยังเบราว์เซอร์ (ในการโหลดฉันจะส่ง)
wsplinter

3
@wsplinter: มันจะช่วยคนอื่นได้ถ้าคุณจัดทำเอกสารการแก้ปัญหาเงื่อนไขเบื้องต้นล้มเหลว
jgauffin

@jgauffin: ฉันจะโพสต์ค่าปุ่มตัวเลือกได้อย่างไร สมมติว่าฉันมีปุ่มตัวเลือก 3 ปุ่มที่อยู่ในกลุ่มเดียวกัน
Asad Refai

1
เห็นได้ชัดว่าสิ่งนี้ไม่ได้ผลสำหรับฉันอย่างที่คาดไว้เนื่องจาก UrlEncode เปลี่ยนสัญลักษณ์เช่น @ เป็นรหัสที่ไม่ได้รับการยอมรับในการเรียก API การเปลี่ยนไปใช้ NameValueCollection เป็น showin ในคำตอบของ @ user3389691 ทำงานได้อย่างสมบูรณ์แบบ
dhruvpatel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.