Comment faire une demande Web HTTP POST

1136

Canonical
Comment puis-je faire une requête HTTP et envoyer des données en utilisant le POST méthode?

Je peux faire une GETdemande, mais je n'ai aucune idée de comment faire une POSTdemande.

Gnôle
la source

Réponses:

2166

Il existe plusieurs façons d'effectuer HTTP GETet des POSTrequêtes:


Méthode A: HttpClient (préféré)

Disponible en: .NET Framework 4.5+, .NET Standard 1.1+,.NET Core 1.0+ .

C'est actuellement l'approche préférée, elle est asynchrone et performante. Utilisez la version intégrée dans la plupart des cas, mais pour les très anciennes plates-formes, il existe un package NuGet .

using System.Net.Http;

Installer

Il est recommandé d'instancier un HttpClientpour la durée de vie de votre application et de le partager, sauf si vous avez une raison spécifique de ne pas le faire.

private static readonly HttpClient client = new HttpClient();

Voir HttpClientFactorypour une solution d' injection de dépendance .


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

Méthode B: bibliothèques tierces

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

Il s'agit d'une bibliothèque plus récente dotée d'une API fluide, testant les assistants, utilise HttpClient sous le capot et est portable. Il est disponible via 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();

Méthode C: HttpWebRequest (non recommandé pour les nouveaux travaux)

Disponible en: .NET Framework 1.1+, .NET Standard 2.0+, .NET Core 1.0+. Dans .NET Core, c'est principalement pour la compatibilité - il encapsule HttpClient, est moins performant et n'obtiendra pas de nouvelles fonctionnalités.

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

Méthode D: WebClient (non recommandé pour les nouveaux travaux)

Ceci est un wrapper autour HttpWebRequest. Comparez avecHttpClient .

Disponible en: .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
la source
2
@Lloyd:HttpWebResponse response = (HttpWebResponse)HttpWReq.GetResponse();
Evan Mulawski
2
Pourquoi utilisez-vous même ASCII? Et si quelqu'un a besoin d'un XML avec UTF-8?
Gero
8
Je déteste battre un cheval mort mais tu devrais le faireresponse.Result.Content.ReadAsStringAsync()
David S.
13
pourquoi avez-vous dit que WebRequest et WebClient sont hérités? MSDN ne dit pas qu'ils sont obsolètes ou quoi que ce soit. Suis-je en train de manquer quelque chose?
Hiep
23
@Hiep: Ils ne sont pas obsolètes, il existe simplement des moyens plus récents (et dans la plupart des cas, meilleurs et plus flexibles) de faire des demandes Web. À mon avis, pour les opérations simples et non critiques, les anciennes méthodes sont très bien - mais cela dépend de vous et de ce que vous êtes le plus à l'aise.
Evan Mulawski
385

Demande GET simple

using System.Net;

...

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

Demande POST simple

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
la source
16
+1 Pour les trucs réguliers POST, il est bon d'avoir un morceau de code aussi court.
user_v
3
Tim - Si vous cliquez avec le bouton droit sur le littéral qui ne peut pas être résolu, vous trouverez un menu contextuel Résoudre, qui contient des actions pour ajouter les instructions Using pour vous. Si le menu contextuel Résolution n'apparaît pas, cela signifie que vous devez d'abord ajouter des références.
Cameron Wilby
J'ai accepté votre réponse comme bonne parce qu'elle est beaucoup plus simple et plus claire.
Hooch
13
Je voudrais ajouter que la variable de réponse pour la demande POST est un tableau d'octets. Pour obtenir la réponse de la chaîne, il vous suffit de faire Encoding.ASCII.GetString (response); (en utilisant System.Text)
Sindre
1
De plus, vous pouvez envoyer un tableau un peu complexe $ _POST ['user'] en tant que: data ["user [username]"] = "myUsername"; data ["user [password]"] = "myPassword";
Bimal Poudel
68

MSDN a un échantillon.

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
la source
Pour une raison quelconque, cela n'a pas fonctionné lorsque
j'envoyais une
26

Ceci est un exemple de travail complet d'envoi / réception de données au format JSON, j'ai utilisé 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
la source
8

Il y a de très bonnes réponses ici. Permettez-moi de publier une manière différente de définir vos en-têtes avec WebClient (). Je vais également vous montrer comment définir une clé 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
la source
Utile, merci. BTW Il semble que la technique ci-dessus pour définir les propriétés d'en-tête fonctionne également pour l'approche HttpWebRequest plus ancienne (obsolète?). par exemple myReq.Headers [HttpRequestHeader.Authorization] = $ "Basic {credentials}";
Zeek2
6

Cette solution n'utilise que des appels .NET standard.

Testé:

  • Utilisé dans une application WPF d'entreprise. Utilise async / wait pour éviter de bloquer l'interface utilisateur.
  • Compatible avec .NET 4.5+.
  • Testé sans paramètres (nécessite un "GET" dans les coulisses).
  • Testé avec des paramètres (nécessite un "POST" dans les coulisses).
  • Testé avec une page Web standard telle que Google.
  • Testé avec un service Web interne basé sur Java.

Référence:

// Add a Reference to the assembly System.Web

Code:

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

Pour appeler sans paramètres (utilise un "GET" dans les coulisses):

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

Pour appeler avec des paramètres (utilise un "POST" dans les coulisses):

 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
la source
6

Solution simple (une ligne, pas de vérification d'erreur, pas d'attente de réponse) que j'ai trouvée jusqu'à présent:

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

Utiliser avec précaution!

Ohad Cohen
la source
5
C'est assez mauvais. Je ne le recommande pas car il n'y a aucune gestion d'erreur et le débogage est pénible. De plus, il existe déjà une excellente réponse à cette question.
Hooch
1
@Hooch d'autres pourraient être intéressés par ce type de réponses, même si ce n'est pas la meilleure.
Mitulát báti
D'accord, le seul contexte dans lequel cela serait utile est le golf à code et qui joue en C #;)
Extragorey
4

Lorsque vous utilisez l' espace de noms Windows.Web.Http , pour POST au lieu de FormUrlEncodedContent, nous écrivons HttpFormUrlEncodedContent. La réponse est également le type de HttpResponseMessage. Le reste est comme l'a écrit Evan Mulawski.

S4NNY1
la source
4

Si vous aimez une API fluide, vous pouvez utiliser Tiny.RestClient . Il est disponible sur 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>();
user8803505
la source
1

Pourquoi n'est-ce pas totalement trivial? Faire la demande n'est pas et surtout ne pas traiter les résultats et il semble que certains bogues .NET soient également impliqués - voir Bug dans HttpClient.GetAsync devrait lever WebException, pas TaskCanceledException

Je me suis retrouvé avec ce code:

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

Cela fera un GET ou POST dépend si postBufferest nul ou non

si le succès est vrai, la réponse sera alors ResponseAsString

Si le succès est faux , vous pouvez vérifier WebExceptionStatus, HttpStatusCodeet ResponseAsStringd'essayer de voir ce qui a mal tourné.

kofifus
la source
0

Dans le noyau .net, vous pouvez effectuer un post-appel avec le code suivant, ici j'ai ajouté quelques fonctionnalités supplémentaires à ce code afin que votre code puisse fonctionner derrière un proxy et avec des informations d'identification réseau le cas échéant, également ici, je mentionne que vous pouvez changer le codage de votre message. J'espère que cela explique tout et vous aide à coder.

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
la source