Як зробити веб-запит HTTP POST


1132

Canonical
Як я можу зробити запит HTTP та надіслати деякі дані за допомогою POST методу?

Я можу зробити GETзапит, але я не маю уявлення про те, як зробити POSTзапит.

Відповіді:


2163

Існує кілька способів виконання 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();
Еван Мулавський

2
Чому ви навіть використовуєте ASCII? Що робити, якщо комусь потрібен xml з UTF-8?
Геро

8
Я ненавиджу бити мертвого коня, але ти повинен це зробитиresponse.Result.Content.ReadAsStringAsync()
Девід С.

13
чому ви сказали, що WebRequest та WebClient є спадщиною? MSDN не каже, що вони застарілі чи що-небудь. Я щось пропускаю?
Hiep

23
@Hiep: Вони не застаріли, є лише новіші (і в більшості випадків кращі та гнучкіші) способи подання веб-запитів. На мою думку, для простих некритичних операцій старі способи просто чудові - але це залежить від вас і того, що вам найбільше подобається.
Еван Мулавський

384

Простий GET-запит

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
Тім - Якщо ви клацніть правою кнопкою миші буква, яку неможливо вирішити, ви знайдете контекстне меню Resolve, яке містить дії для додавання для вас операторів Use. Якщо контекстне меню Resolve не відображається, це означає, що потрібно спочатку додати посилання.
Камерон Вілбі

Я прийняв вашу відповідь як добру, тому що вона набагато простіша і зрозуміліша.
Гуч

13
Я хотів би додати, що змінна відповіді на запит POST - це масив байтів. Для отримання відповіді рядка ви просто зробите Encoding.ASCII.GetString (відповідь); (використовуючи System.Text)
Сіндр

1
Крім того, ви можете надіслати трохи складний масив $ _POST ['user'] у вигляді: data ["user [username]"] = "myUsername"; data ["user [password]"] = "myPassword";
Бімал Поудель

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. Використовує асинхронізацію / очікування, щоб уникнути блокування інтерфейсу користувача.
  • Сумісний з .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

Просте (однолінійний, без перевірки помилок, немає очікування відповіді), яке я знайшов досі:

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

Використовуйте обережно!


5
Це зовсім погано. Я не рекомендую це, оскільки немає жодних помилок, а налагодження - це біль. Крім того, тут вже є чудова відповідь на це питання.
Hooch

1
@Hooch інших може зацікавити такий тип відповідей, навіть якщо це не найкращий варіант.
Mitulát báti

Домовились, єдиний контекст, в якому це було б корисно - це гольф з кодом та хто гольфує в C #;)
Екстрагорей

4

Під час використання простору імен Windows.Web.Http для POST замість FormUrlEncodedContent пишемо HttpFormUrlEncodedContent. Також відповідь - тип HttpResponseMessage. Решта - як записав Еван Мулавський.


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 ви можете здійснювати післядзвінок із наступним кодом, тут я додав кілька додаткових функцій до цього коду, щоб змусити ваш код працювати за проксі-сервером та за допомогою мережевих облікових даних, якщо такі є, також тут я зазначу, що ви можете змінити кодування Ваше повідомлення. Я сподіваюся, що це все пояснює і допоможе вам у кодуванні.

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;
        }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.