วิธีสร้างคำขอ HTTP POST บนเว็บ


1133

Canonical
ฉันจะขอ HTTP และส่งข้อมูลบางอย่างโดยใช้ POST วิธีได้อย่างไร

ฉันสามารถทำGETคำขอได้ แต่ฉันไม่มีความคิดเกี่ยวกับวิธีการPOSTร้องขอ

คำตอบ:


2165

มีหลายวิธีในการดำเนินการ HTTP GETและPOSTคำขอ:


วิธี A: HttpClient (ต้องการ)

.NET Framework 4.5+ที่มีจำหน่ายใน: .NET Standard 1.1+, .NET Core 1.0+,

ปัจจุบันเป็นวิธีการที่ต้องการและไม่ตรงกันและมีประสิทธิภาพสูง ใช้ในตัวรุ่นในกรณีส่วนใหญ่ แต่สำหรับแพลตฟอร์มเก่ามากมีแพคเกจ NuGet

using System.Net.Http;

ติดตั้ง

ขอแนะนำให้สร้างอินสแตนซ์หนึ่งHttpClientสำหรับอายุการใช้งานของแอปพลิเคชันของคุณและแชร์เว้นแต่คุณจะมีเหตุผลเฉพาะที่ไม่ควรทำ

private static readonly HttpClient client = new HttpClient();

ดูHttpClientFactoryวิธีการแก้ปัญหาการฉีดพึ่งพา


  • POST

    var values = new Dictionary<string, string>
    {
        { "thing1", "hello" },
        { "thing2", "world" }
    };
    
    var content = new FormUrlEncodedContent(values);
    
    var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
    
    var responseString = await response.Content.ReadAsStringAsync();
  • GET

    var responseString = await client.GetStringAsync("http://www.example.com/recepticle.aspx");

วิธี B: ไลบรารีของบุคคลที่สาม

RestSharp

  • POST

     var client = new RestClient("http://example.com");
     // client.Authenticator = new HttpBasicAuthenticator(username, password);
     var request = new RestRequest("resource/{id}");
     request.AddParameter("thing1", "Hello");
     request.AddParameter("thing2", "world");
     request.AddHeader("header", "value");
     request.AddFile("file", path);
     var response = client.Post(request);
     var content = response.Content; // Raw content as string
     var response2 = client.Post<Person>(request);
     var name = response2.Data.Name;

Flurl.Http

มันเป็นห้องสมุดที่ใหม่กว่าที่มี API ที่คล่องแคล่วทดสอบผู้ช่วยใช้ HttpClient ภายใต้ประทุนและเป็นแบบพกพา มันสามารถใช้ได้ผ่านNuGet

    using Flurl.Http;

  • POST

    var responseString = await "http://www.example.com/recepticle.aspx"
        .PostUrlEncodedAsync(new { thing1 = "hello", thing2 = "world" })
        .ReceiveString();
  • GET

    var responseString = await "http://www.example.com/recepticle.aspx"
        .GetStringAsync();

วิธี C: HttpWebRequest (ไม่แนะนำสำหรับงานใหม่)

.NET Framework 1.1+ที่มีจำหน่ายใน: .NET Standard 2.0+, .NET Core 1.0+, ใน. NET Core เป็นส่วนใหญ่สำหรับความเข้ากันได้ - มันล้อมรอบHttpClientมีประสิทธิภาพน้อยกว่าและจะไม่ได้รับคุณสมบัติใหม่

using System.Net;
using System.Text;  // For class Encoding
using System.IO;    // For StreamReader

  • POST

    var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");
    
    var postData = "thing1=" + Uri.EscapeDataString("hello");
        postData += "&thing2=" + Uri.EscapeDataString("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();
  • GET

    var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");
    
    var response = (HttpWebResponse)request.GetResponse();
    
    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

วิธี D: WebClient (ไม่แนะนำสำหรับงานใหม่)

HttpWebRequestนี่คือเสื้อคลุมรอบ เปรียบกับHttpClient

ที่มีจำหน่ายใน: .NET Framework 1.1+, NET Standard 2.0+,.NET Core 2.0+

using System.Net;
using System.Collections.Specialized;

  • POST

    using (var client = new WebClient())
    {
        var values = new NameValueCollection();
        values["thing1"] = "hello";
        values["thing2"] = "world";
    
        var response = client.UploadValues("http://www.example.com/recepticle.aspx", values);
    
        var responseString = Encoding.Default.GetString(response);
    }
  • GET

    using (var client = new WebClient())
    {
        var responseString = client.DownloadString("http://www.example.com/recepticle.aspx");
    }

2
@Lloyd:HttpWebResponse response = (HttpWebResponse)HttpWReq.GetResponse();
Evan Mulawski

2
ทำไมคุณถึงใช้ ASCII เกิดอะไรขึ้นถ้ามีคนต้องการ xml ด้วย UTF-8
Gero

8
ฉันเกลียดที่จะเอาชนะม้าที่ตายแล้ว แต่คุณควรทำอย่างไรresponse.Result.Content.ReadAsStringAsync()
เดวิดเอส

13
ทำไมคุณถึงบอกว่า WebRequest และ WebClient เป็นมรดก? MSDN ไม่ได้บอกว่าพวกเขาเลิกใช้แล้วหรืออะไรก็ตาม ฉันพลาดอะไรไปรึเปล่า?
สวัสดี

23
@Hiep: พวกเขาจะไม่คัดค้านมีเพียงใหม่ (และเป็นกรณีส่วนใหญ่ดีกว่าและมีความยืดหยุ่นมากขึ้น) วิธีการร้องขอเว็บ ในความคิดของฉันสำหรับการดำเนินการที่เรียบง่ายและไม่สำคัญวิธีการเดิมนั้นใช้ได้ - แต่ขึ้นอยู่กับคุณและสิ่งที่คุณพอใจที่สุด
Evan Mulawski

384

รับคำของ่ายๆ

using System.Net;

...

using (var wb = new WebClient())
{
    var response = wb.DownloadString(url);
}

คำขอ POST ง่าย ๆ

using System.Net;
using System.Collections.Specialized;

...

using (var wb = new WebClient())
{
    var data = new NameValueCollection();
    data["username"] = "myUser";
    data["password"] = "myPassword";

    var response = wb.UploadValues(url, "POST", data);
    string responseInString = Encoding.UTF8.GetString(response);
}

15
+1 สำหรับสิ่งปกติ POST เป็นการดีถ้ามีรหัสย่อ ๆ
user_v

3
Tim - หากคุณคลิกขวาที่ตัวอักษรที่ไม่สามารถแก้ไขได้คุณจะพบเมนูบริบทแก้ไขซึ่งมีการดำเนินการเพื่อเพิ่มคำสั่ง Using สำหรับคุณ หากเมนูบริบทแก้ไขไม่ปรากฏขึ้นหมายความว่าคุณต้องเพิ่มการอ้างอิงก่อน
Cameron Wilby

ฉันยอมรับคำตอบของคุณดีเพราะมันง่ายกว่าและชัดเจนกว่ามาก
Hooch

13
ฉันต้องการเพิ่มว่าตัวแปรตอบกลับสำหรับคำขอ POST เป็นอาร์เรย์ไบต์ ในการรับการตอบกลับสตริงคุณเพียงแค่ทำการเข้ารหัส Encoding.ASCII.GetString (การตอบกลับ); (ใช้ System.Text)
Sindre

1
นอกจากนี้คุณสามารถส่งอาร์เรย์ที่ซับซ้อนได้ $ _POST ['user'] เป็น: data ["user [ชื่อผู้ใช้]"] = "myUsername"; data ["user [password]"] = "myPassword";
Bimal Poudel

68

MSDNมีตัวอย่าง

using System;
using System.IO;
using System.Net;
using System.Text;

namespace Examples.System.Net
{
    public class WebRequestPostExample
    {
        public static void Main()
        {
            // Create a request using a URL that can receive a post. 
            WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx");
            // Set the Method property of the request to POST.
            request.Method = "POST";
            // Create POST data and convert it to a byte array.
            string postData = "This is a test that posts this string to a Web server.";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Set the ContentType property of the WebRequest.
            request.ContentType = "application/x-www-form-urlencoded";
            // Set the ContentLength property of the WebRequest.
            request.ContentLength = byteArray.Length;
            // Get the request stream.
            Stream dataStream = request.GetRequestStream();
            // Write the data to the request stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Close the Stream object.
            dataStream.Close();
            // Get the response.
            WebResponse response = request.GetResponse();
            // Display the status.
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            // Get the stream containing content returned by the server.
            dataStream = response.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            // Display the content.
            Console.WriteLine(responseFromServer);
            // Clean up the streams.
            reader.Close();
            dataStream.Close();
            response.Close();
        }
    }
}

ด้วยเหตุผลบางอย่างมันไม่ทำงานเมื่อฉันส่งข้อมูลจำนวนมาก
AnKing

26

นี่เป็นตัวอย่างการทำงานที่สมบูรณ์ของการส่ง / รับข้อมูลในรูปแบบ JSON ฉันใช้Visual Studio 2013 Express Edition:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
    }

    public class Program
    {
        private static readonly HttpClient _Client = new HttpClient();
        private static JavaScriptSerializer _Serializer = new JavaScriptSerializer();

        static void Main(string[] args)
        {
            Run().Wait();
        }

        static async Task Run()
        {
            string url = "http://www.example.com/api/Customer";
            Customer cust = new Customer() { Name = "Example Customer", Address = "Some example address", Phone = "Some phone number" };
            var json = _Serializer.Serialize(cust);
            var response = await Request(HttpMethod.Post, url, json, new Dictionary<string, string>());
            string responseText = await response.Content.ReadAsStringAsync();

            List<YourCustomClassModel> serializedResult = _Serializer.Deserialize<List<YourCustomClassModel>>(responseText);

            Console.WriteLine(responseText);
            Console.ReadLine();
        }

        /// <summary>
        /// Makes an async HTTP Request
        /// </summary>
        /// <param name="pMethod">Those methods you know: GET, POST, HEAD, etc...</param>
        /// <param name="pUrl">Very predictable...</param>
        /// <param name="pJsonContent">String data to POST on the server</param>
        /// <param name="pHeaders">If you use some kind of Authorization you should use this</param>
        /// <returns></returns>
        static async Task<HttpResponseMessage> Request(HttpMethod pMethod, string pUrl, string pJsonContent, Dictionary<string, string> pHeaders)
        {
            var httpRequestMessage = new HttpRequestMessage();
            httpRequestMessage.Method = pMethod;
            httpRequestMessage.RequestUri = new Uri(pUrl);
            foreach (var head in pHeaders)
            {
                httpRequestMessage.Headers.Add(head.Key, head.Value);
            }
            switch (pMethod.Method)
            {
                case "POST":
                    HttpContent httpContent = new StringContent(pJsonContent, Encoding.UTF8, "application/json");
                    httpRequestMessage.Content = httpContent;
                    break;

            }

            return await _Client.SendAsync(httpRequestMessage);
        }
    }
}

8

มีคำตอบที่ดีจริงๆอยู่ที่นี่ ให้ฉันโพสต์วิธีอื่นในการตั้งค่าส่วนหัวของคุณด้วย WebClient () ฉันจะแสดงวิธีตั้งค่าคีย์ API ด้วย

        var client = new WebClient();
        string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord));
        client.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";
        //If you have your data stored in an object serialize it into json to pass to the webclient with Newtonsoft's JsonConvert
        var encodedJson = JsonConvert.SerializeObject(newAccount);

        client.Headers.Add($"x-api-key:{ApiKey}");
        client.Headers.Add("Content-Type:application/json");
        try
        {
            var response = client.UploadString($"{apiurl}", encodedJson);
            //if you have a model to deserialize the json into Newtonsoft will help bind the data to the model, this is an extremely useful trick for GET calls when you have a lot of data, you can strongly type a model and dump it into an instance of that class.
            Response response1 = JsonConvert.DeserializeObject<Response>(response);

มีประโยชน์ขอบคุณ BTW ดูเหมือนว่าเทคนิคข้างต้นสำหรับการตั้งค่าส่วนหัวคุณสมบัติยังใช้งานได้สำหรับวิธีเก่า (คัดค้าน?) วิธี HttpWebRequest เช่น myReq.Headers [HttpRequestHeader.Authorization] = $ "พื้นฐาน {หนังสือรับรอง}";
Zeek2

6

วิธีนี้ใช้ไม่ได้เลยยกเว้นการเรียก. NET แบบมาตรฐาน

การทดสอบ:

  • ใช้ในแอปพลิเคชันองค์กร WPF ใช้ async / รอคอยเพื่อหลีกเลี่ยงการบล็อก UI
  • เข้ากันได้กับ. NET 4.5+
  • ทดสอบโดยไม่มีพารามิเตอร์ (ต้องใช้ "GET" หลังฉาก)
  • ทดสอบกับพารามิเตอร์ (ต้องมี "POST" หลังฉาก)
  • ทดสอบกับหน้าเว็บมาตรฐานเช่น Google
  • ทดสอบกับเว็บเซอร์ภายใน Java

อ้างอิง:

// Add a Reference to the assembly System.Web

รหัส:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;

private async Task<WebResponse> CallUri(string url, TimeSpan timeout)
{
    var uri = new Uri(url);
    NameValueCollection rawParameters = HttpUtility.ParseQueryString(uri.Query);
    var parameters = new Dictionary<string, string>();
    foreach (string p in rawParameters.Keys)
    {
        parameters[p] = rawParameters[p];
    }

    var client = new HttpClient { Timeout = timeout };
    HttpResponseMessage response;
    if (parameters.Count == 0)
    {
        response = await client.GetAsync(url);
    }
    else
    {
        var content = new FormUrlEncodedContent(parameters);
        string urlMinusParameters = uri.OriginalString.Split('?')[0]; // Parameters always follow the '?' symbol.
        response = await client.PostAsync(urlMinusParameters, content);
    }
    var responseString = await response.Content.ReadAsStringAsync();

    return new WebResponse(response.StatusCode, responseString);
}

private class WebResponse
{
    public WebResponse(HttpStatusCode httpStatusCode, string response)
    {
        this.HttpStatusCode = httpStatusCode;
        this.Response = response;
    }
    public HttpStatusCode HttpStatusCode { get; }
    public string Response { get; }
}

ในการโทรโดยไม่มีพารามิเตอร์ (ใช้ "GET" หลังฉาก):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://www.google.com/", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

วิธีเรียกใช้ด้วยพารามิเตอร์ (ใช้ "POST" ด้านหลังฉาก):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://example.com/path/to/page?name=ferret&color=purple", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

6

Simple (one-liner, ไม่มีการตรวจสอบข้อผิดพลาด, ไม่ต้องรอการตอบกลับ) โซลูชันที่ฉันพบ:

(new WebClient()).UploadStringAsync(new Uri(Address), dataString);‏

ใช้ด้วยความระมัดระวัง!


5
นั่นค่อนข้างแย่ ฉันไม่แนะนำเพราะไม่มีข้อผิดพลาดในการจัดการใด ๆ และแก้จุดบกพร่องมันเจ็บปวด นอกจากนี้ยังมีคำตอบที่ดีสำหรับคำถามนี้
Hooch

1
@ กอดคนอื่นอาจสนใจคำตอบประเภทนี้แม้ว่าจะไม่ใช่คำตอบที่ดีที่สุดก็ตาม
Mitulátbáti

เห็นด้วยบริบทเดียวที่จะเป็นประโยชน์คือการเขียนโค้ดกอล์ฟและผู้เล่นกอล์ฟใน C #;)
Extragorey

4

เมื่อใช้Windows.Web.Http namespace สำหรับ POST แทน FormUrlEncodedContent เราจะเขียน HttpFormUrlEncodedContent นอกจากนี้การตอบสนองเป็นประเภทของ HttpResponseMessage ที่เหลือก็คือ Evan Mulawski ที่จดไว้


4

ถ้าคุณชอบได้อย่างคล่องแคล่ว API คุณสามารถใช้Tiny.RestClient มันมีอยู่ในNuGet

var client = new TinyRestClient(new HttpClient(), "http://MyAPI.com/api");
// POST
var city = new City() { Name = "Paris", Country = "France" };
// With content
var response = await client.PostRequest("City", city)
                           .ExecuteAsync<bool>();

1

ทำไมสิ่งนี้จึงไม่สำคัญเลย? การทำคำขอไม่ได้และโดยเฉพาะอย่างยิ่งไม่ได้เกี่ยวข้องกับผลลัพธ์และดูเหมือนว่ามีข้อผิดพลาด. NET บางส่วนที่เกี่ยวข้องเช่นกัน - ดูข้อผิดพลาดใน HttpClient.GetAsync ควรโยน WebException ไม่ใช่ TaskCanceledException

ฉันลงเอยด้วยรหัสนี้:

static async Task<(bool Success, WebExceptionStatus WebExceptionStatus, HttpStatusCode? HttpStatusCode, string ResponseAsString)> HttpRequestAsync(HttpClient httpClient, string url, string postBuffer = null, CancellationTokenSource cts = null) {
    try {
        HttpResponseMessage resp = null;

        if (postBuffer is null) {
            resp = cts is null ? await httpClient.GetAsync(url) : await httpClient.GetAsync(url, cts.Token);

        } else {
            using (var httpContent = new StringContent(postBuffer)) {
                resp = cts is null ? await httpClient.PostAsync(url, httpContent) : await httpClient.PostAsync(url, httpContent, cts.Token);
            }
        }

        var respString = await resp.Content.ReadAsStringAsync();
        return (resp.IsSuccessStatusCode, WebExceptionStatus.Success, resp.StatusCode, respString);

    } catch (WebException ex) {
        WebExceptionStatus status = ex.Status;
        if (status == WebExceptionStatus.ProtocolError) {
            // Get HttpWebResponse so that you can check the HTTP status code.
            using (HttpWebResponse httpResponse = (HttpWebResponse)ex.Response) {
                return (false, status, httpResponse.StatusCode, httpResponse.StatusDescription);
            }
        } else {
            return (false, status, null, ex.ToString()); 
        }

    } catch (TaskCanceledException ex) {
        if (cts is object && ex.CancellationToken == cts.Token) {
            // a real cancellation, triggered by the caller
            return (false, WebExceptionStatus.RequestCanceled, null, ex.ToString());
        } else {
            // a web request timeout (possibly other things!?)
            return (false, WebExceptionStatus.Timeout, null, ex.ToString());
        }

    } catch (Exception ex) {
        return (false, WebExceptionStatus.UnknownError, null, ex.ToString());
    }
}

สิ่งนี้จะทำ GET หรือ POST ขึ้นอยู่กับว่าpostBufferเป็นโมฆะหรือไม่

หากความสำเร็จเป็นจริงคำตอบก็จะอยู่ในนั้น ResponseAsString

ถ้าประสบความสำเร็จเป็นเท็จคุณสามารถตรวจสอบWebExceptionStatus, HttpStatusCodeและResponseAsStringพยายามที่จะเห็นสิ่งที่ผิดพลาดไป


0

ใน. net core คุณสามารถทำการ post-call ด้วยรหัสต่อไปนี้ที่นี่ฉันได้เพิ่มคุณสมบัติพิเศษบางอย่างในรหัสนี้เพื่อให้รหัสของคุณทำงานหลังพร็อกซีและมีข้อมูลประจำตัวเครือข่ายถ้ามีที่นี่ฉันพูดถึงว่าคุณสามารถเปลี่ยนการเข้ารหัส ข้อความของคุณ. ฉันหวังว่าสิ่งนี้จะอธิบายทั้งหมดและช่วยคุณในการเขียนโปรแกรม

HttpClient client = GetHttpClient(_config);

        if (headers != null)
        {
            foreach (var header in headers)
            {
                client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
            }
        }

        client.BaseAddress = new Uri(baseAddress);

        Encoding encoding = Encoding.UTF8;


        var result = await client.PostAsync(url, new StringContent(body, encoding, "application/json")).ConfigureAwait(false);
        if (result.IsSuccessStatusCode)
        {
            return new RequestResponse { severity = "Success", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
        }
        else
        {
            return new RequestResponse { severity = "failure", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
        }


 public HttpClient GetHttpClient(IConfiguration _config)
        {
            bool ProxyEnable = Convert.ToBoolean(_config["GlobalSettings:ProxyEnable"]);

            HttpClient client = null;
            if (!ProxyEnable)
            {
                client = new HttpClient();
            }
            else
            {
                string ProxyURL = _config["GlobalSettings:ProxyURL"];
                string ProxyUserName = _config["GlobalSettings:ProxyUserName"];
                string ProxyPassword = _config["GlobalSettings:ProxyPassword"];
                string[] ExceptionURL = _config["GlobalSettings:ExceptionURL"].Split(';');
                bool BypassProxyOnLocal = Convert.ToBoolean(_config["GlobalSettings:BypassProxyOnLocal"]);
                bool UseDefaultCredentials = Convert.ToBoolean(_config["GlobalSettings:UseDefaultCredentials"]);

                WebProxy proxy = new WebProxy
                {
                    Address = new Uri(ProxyURL),
                    BypassProxyOnLocal = BypassProxyOnLocal,
                    UseDefaultCredentials = UseDefaultCredentials,
                    BypassList = ExceptionURL,
                    Credentials = new NetworkCredential(ProxyUserName, ProxyPassword)

                };

                HttpClientHandler handler = new HttpClientHandler { Proxy = proxy };
                client = new HttpClient(handler,true);
            }
            return client;
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.