Come effettuare una richiesta Web POST HTTP


1134

Canonico
Come posso fare una richiesta HTTP e inviare alcuni dati usando il POST metodo?

Posso fare una GETrichiesta, ma non ho idea di come fare una POSTrichiesta.

Risposte:


2166

Esistono diversi modi per eseguire HTTP GETe POSTrichieste:


Metodo A: HttpClient (preferito)

Disponibile in: .NET Framework 4.5+, .NET Standard 1.1+, .NET Core 1.0+.

Attualmente è l'approccio preferito, asincrono e ad alte prestazioni. Utilizza la versione integrata nella maggior parte dei casi, ma per piattaforme molto vecchie esiste un pacchetto NuGet .

using System.Net.Http;

Impostare

Si consiglia di creare un'istanza HttpClientper la durata dell'applicazione e condividerla a meno che non si abbia un motivo specifico per non farlo.

private static readonly HttpClient client = new HttpClient();

Vedere HttpClientFactoryper una soluzione di iniezione di dipendenza .


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

Metodo B: librerie di terze parti

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

È una libreria più recente con un'API fluente, che verifica gli helper, utilizza HttpClient sotto il cofano ed è portatile. È disponibile tramite 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();

Metodo C: HttpWebRequest (non consigliato per nuovi lavori)

Disponibile in: .NET Framework 1.1+, .NET Standard 2.0+, .NET Core 1.0+. In .NET Core è principalmente per compatibilità: si avvolge HttpClient, è meno performante e non otterrà nuove funzionalità.

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

Metodo D: WebClient (non consigliato per nuovi lavori)

Questo è un involucro in giro HttpWebRequest. Confronta conHttpClient .

Disponibile in: .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 il

2
Perché usi anche ASCII? Cosa succede se qualcuno ha bisogno di un XML con UTF-8?
Gero,

8
Odio battere un cavallo morto ma dovresti farloresponse.Result.Content.ReadAsStringAsync()
David S.

13
perché hai detto che WebRequest e WebClient sono legacy? MSDN non dice che sono deprecati o altro. Mi sto perdendo qualcosa?
Hiep,

23
@Hiep: non sono deprecati, ci sono solo modi più nuovi (e nella maggior parte dei casi, migliori e più flessibili) di effettuare richieste Web. Secondo me, per operazioni semplici e non critiche, i vecchi metodi vanno bene, ma dipende da te e da qualunque cosa tu sia a tuo agio.
Evan Mulawski,

385

Richiesta GET semplice

using System.Net;

...

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

Richiesta POST semplice

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

16
+1 Per roba normale POST è bello avere un codice così breve.
user_v

3
Tim: se fai clic con il pulsante destro del mouse sul valore letterale che non può essere risolto, troverai un menu di scelta rapida Risolvi, che contiene le azioni per aggiungere le istruzioni Using per te. Se il menu di scelta rapida Risolvi non viene visualizzato, significa che devi prima aggiungere riferimenti.
Cameron Wilby,

Ho accettato la tua risposta come buona perché è molto più semplice e chiara.
Hooch,

13
Vorrei aggiungere che la variabile di risposta per la richiesta POST è un array di byte. Per ottenere la risposta della stringa basta eseguire Encoding.ASCII.GetString (response); (usando System.Text)
Sindre,

1
Inoltre, puoi inviare un array un po 'complesso $ _POST [' user '] come: data ["user [username]"] = "myUsername"; data ["user [password]"] = "myPassword";
Bimal Poudel,

68

MSDN ha un campione.

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

Per qualche motivo non funzionava quando stavo inviando una grande quantità di dati
AnKing,

26

Questo è un esempio funzionante completo di invio / ricezione di dati in formato JSON, ho usato 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

Ci sono alcune risposte davvero valide qui. Consentitemi di pubblicare un modo diverso di impostare le intestazioni con WebClient (). Ti mostrerò anche come impostare una chiave 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);

Utile grazie. A proposito, sembra che la tecnica sopra descritta per impostare le proprietà di intestazione funzioni anche per l'approccio HttpWebRequest precedente (obsoleto?). ad esempio myReq.Headers [HttpRequestHeader.Authorization] = $ "Basic {credentials}";
Zeek2,

6

Questa soluzione non utilizza altro che chiamate .NET standard.

Provato:

  • In uso in un'applicazione WPF aziendale. Utilizza asincrono / attendi per evitare il blocco dell'interfaccia utente.
  • Compatibile con .NET 4.5+.
  • Testato senza parametri (richiede un "GET" dietro le quinte).
  • Testato con parametri (richiede un "POST" dietro le quinte).
  • Testato con una pagina Web standard come Google.
  • Testato con un servizio Web interno basato su Java.

Riferimento:

// Add a Reference to the assembly System.Web

Codice:

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

Per chiamare senza parametri (utilizza un "GET" dietro le quinte):

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

Per chiamare con i parametri (usa un "POST" dietro le quinte):

 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

Soluzione semplice (one-liner, nessun controllo errori, nessuna attesa di risposta) che ho trovato finora:

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

Usare con cautela!


5
Questo è abbastanza male. Non lo consiglio in quanto non esiste alcun errore nella gestione di alcun tipo e il debug è doloroso. Inoltre c'è già un'ottima risposta a questa domanda.
Hooch,

1
@ Altri potrebbero essere interessati a questo tipo di risposte, anche se non è la migliore.
Mitulát báti,

D'accordo, l'unico contesto in cui questo sarebbe utile è il golf di codice e chi gioca a golf in C #;)
Extragorey,

4

Quando si utilizza lo spazio dei nomi Windows.Web.Http , per POST anziché FormUrlEncodedContent scriviamo HttpFormUrlEncodedContent. Anche la risposta è il tipo di HttpResponseMessage. Il resto è come ha scritto Evan Mulawski.


4

Se ti piace un'API fluente puoi usare Tiny.RestClient . È disponibile su 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

Perché questo non è del tutto banale? Fare la richiesta non è e soprattutto non si occupa dei risultati e sembra che ci siano anche alcuni bug di .NET. Vedi Bug in HttpClient.GetAsync dovrebbe lanciare WebException, non TaskCanceledException

Ho finito con questo codice:

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

Questo farà un GET o POST dipende se postBufferè nullo o no

se il successo è vero, allora la risposta sarà dentro ResponseAsString

se il successo è falso è possibile controllare WebExceptionStatus, HttpStatusCodee ResponseAsStringper cercare di vedere cosa è andato storto.


0

In .net core puoi effettuare la post-chiamata con il seguente codice, qui ho aggiunto alcune funzionalità extra a questo codice in modo da far funzionare il tuo codice dietro un proxy e con eventuali credenziali di rete, anche qui menziono che puoi cambiare la codifica di il tuo messaggio. Spero che questo spieghi tutto e ti aiuti nella programmazione.

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;
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.