Cara membuat permintaan web HTTP POST

1134

Canonical
Bagaimana saya bisa membuat permintaan HTTP dan mengirim beberapa data menggunakan POST metode ini?

Saya dapat melakukan GETpermintaan, tetapi saya tidak tahu bagaimana cara membuat POSTpermintaan.

Hooch
sumber

Jawaban:

2166

Ada beberapa cara untuk melakukan HTTP GETdan POSTpermintaan:


Metode A: HttpClient (Lebih disukai)

Tersedia dalam: .NET Framework 4.5+, .NET Standard 1.1+, .NET Core 1.0+.

Saat ini pendekatan yang disukai, dan tidak sinkron dan berkinerja tinggi. Dalam kebanyakan kasus, gunakan versi bawaan , tetapi untuk platform yang sangat lama ada paket NuGet .

using System.Net.Http;

Mendirikan

Disarankan untuk instantiate satu HttpClientuntuk seumur hidup aplikasi Anda dan membaginya kecuali Anda memiliki alasan khusus untuk tidak melakukannya.

private static readonly HttpClient client = new HttpClient();

Lihat HttpClientFactoryuntuk solusi injeksi ketergantungan .


  • 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");

Metode B: Perpustakaan Pihak Ketiga

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

Ini adalah perpustakaan baru yang menggunakan API yang lancar, menguji bantuan, menggunakan HttpClient di bawah tenda, dan portabel. Ini tersedia melalui 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();
    

Metode C: HttpWebRequest (tidak disarankan untuk pekerjaan baru)

Tersedia dalam: .NET Framework 1.1+, .NET Standard 2.0+, .NET Core 1.0+. Dalam .NET Core, sebagian besar untuk kompatibilitas - membungkus HttpClient, kurang berkinerja, dan tidak akan mendapatkan fitur baru.

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();
    

Metode D: WebClient (Tidak disarankan untuk pekerjaan baru)

Ini adalah pembungkus HttpWebRequest. Bandingkan denganHttpClient .

Tersedia dalam: .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");
    }
    
Evan Mulawski
sumber
2
@Lloyd:HttpWebResponse response = (HttpWebResponse)HttpWReq.GetResponse();
Evan Mulawski
2
Mengapa Anda bahkan menggunakan ASCII? Bagaimana jika seseorang membutuhkan xml dengan UTF-8?
Gero
8
Saya benci memukuli kuda mati tetapi Anda harus melakukannyaresponse.Result.Content.ReadAsStringAsync()
David S.
13
mengapa Anda mengatakan WebRequest dan WebClient adalah warisan? MSDN tidak mengatakan bahwa mereka sudah usang atau apa pun. Apakah saya melewatkan sesuatu?
Hiep
23
@ Hiep: Mereka tidak usang, hanya ada cara yang lebih baru (dan kebanyakan kasus, lebih baik dan lebih fleksibel) untuk membuat permintaan web. Menurut pendapat saya, untuk operasi sederhana dan non-kritis, cara-cara lama baik-baik saja - tetapi terserah Anda dan apa pun yang paling nyaman bagi Anda.
Evan Mulawski
385

Permintaan GET sederhana

using System.Net;

...

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

Permintaan POST sederhana

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);
}
Pavlo Neiman
sumber
16
+1 Untuk hal-hal biasa POST, sangat bagus memiliki sepotong kode pendek.
user_v
3
Tim - Jika Anda mengklik kanan literal yang tidak dapat diselesaikan, Anda akan menemukan menu konteks Putuskan, yang berisi tindakan untuk menambahkan pernyataan Menggunakan untuk Anda. Jika menu Atasi konteks tidak muncul, itu berarti Anda perlu menambahkan referensi terlebih dahulu.
Cameron Wilby
Saya menerima jawaban Anda dengan baik karena jauh lebih sederhana dan jelas.
Hooch
13
Saya ingin menambahkan bahwa variabel respons untuk permintaan POST adalah array byte. Untuk mendapatkan respons string, Anda cukup melakukan Encoding.ASCII.GetString (response); (Menggunakan System.Text)
Sindre
1
Selanjutnya, Anda dapat mengirim array yang sedikit rumit $ _POST ['user'] sebagai: data ["user [username]"] = "myUsername"; data ["user [kata sandi]"] = "myPassword";
Bimal Poudel
68

MSDN memiliki sampel.

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();
        }
    }
}
Otávio Décio
sumber
Untuk beberapa alasan itu tidak berfungsi ketika saya mengirim sejumlah besar data
AnKing
26

Ini adalah contoh kerja lengkap mengirim / menerima data dalam format JSON, saya menggunakan 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);
        }
    }
}
Ivanzinho
sumber
8

Ada beberapa jawaban yang sangat bagus di sini. Biarkan saya memposting cara berbeda untuk mengatur tajuk Anda dengan WebClient (). Saya juga akan menunjukkan kepada Anda bagaimana mengatur kunci 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);
Adam
sumber
Berguna, terima kasih. BTW Sepertinya teknik di atas untuk mengatur header-properties juga berfungsi untuk yang lebih lama (usang?), Pendekatan HttpWebRequest. mis. myReq.Headers [HttpRequestHeader.Authorization] = $ "Basic {credentials}";
Zeek2
6

Solusi ini hanya menggunakan panggilan .NET standar.

Diuji:

  • Digunakan dalam aplikasi WPF perusahaan. Gunakan async / tunggu untuk menghindari pemblokiran UI.
  • Kompatibel dengan .NET 4.5+.
  • Diuji tanpa parameter (memerlukan "GET" di belakang layar).
  • Diuji dengan parameter (memerlukan "POST" di belakang layar).
  • Diuji dengan halaman web standar seperti Google.
  • Diuji dengan layanan web internal berbasis Java.

Referensi:

// Add a Reference to the assembly System.Web

Kode:

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; }
}

Untuk memanggil tanpa parameter (gunakan "GET" di belakang layar):

 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.
 }

Untuk memanggil dengan parameter (menggunakan "POST" di belakang layar):

 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.
 }
Contango
sumber
6

Solusi sederhana (satu garis, tanpa pengecekan kesalahan, tidak menunggu respons) yang saya temukan sejauh ini:

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

Gunakan dengan hati-hati!

Ohad Cohen
sumber
5
Itu sangat buruk. Saya tidak merekomendasikan ini karena tidak ada kesalahan penanganan apapun dan debugging itu menyakitkan. Selain itu sudah ada jawaban bagus untuk pertanyaan ini.
Hooch
1
@Hooch, orang lain mungkin tertarik dengan jenis jawaban ini, meskipun itu bukan yang terbaik.
Mitulát báti
Setuju, satu-satunya konteks di mana ini akan berguna adalah kode golf dan siapa yang bermain golf di C #;)
Extragorey
4

Saat menggunakan namespace Windows.Web.Http , untuk POST alih-alih FormUrlEncodedContent kita menulis HttpFormUrlEncodedContent. Juga tanggapannya adalah tipe HttpResponseMessage. Sisanya adalah seperti yang ditulis Evan Mulawski.

S4NNY1
sumber
4

Jika Anda menyukai API yang lancar, Anda dapat menggunakan Tiny.RestClient . Ini tersedia di 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>();
pengguna8803505
sumber
1

Mengapa ini tidak sepenuhnya sepele? Melakukan permintaan tidak dan terutama tidak berurusan dengan hasil dan sepertinya ada beberapa. NET bug yang terlibat juga - lihat Bug di HttpClient.GetAsync harus membuang WebException, bukan TaskCanceledException

Saya berakhir dengan kode ini:

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());
    }
}

Ini akan melakukan GET atau POST tergantung apakah postBufferitu nol atau tidak

jika Sukses benar, maka responsnya akan masuk ResponseAsString

jika Sukses salah Anda dapat memeriksa WebExceptionStatus, HttpStatusCodedan ResponseAsStringuntuk mencoba melihat apa yang salah.

kofifus
sumber
0

Di .net inti Anda dapat membuat panggilan-post dengan kode berikut, di sini saya menambahkan beberapa fitur tambahan untuk kode ini sehingga dapat membuat kode Anda bekerja di belakang proxy dan dengan kredensial jaringan jika ada, juga di sini saya menyebutkan bahwa Anda dapat mengubah pengkodean pesan Anda. Saya harap ini menjelaskan semuanya dan membantu Anda dalam pengkodean.

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;
        }
Syed Fahad Ali
sumber